Проверка на равенство
Часть раздела Object Oriented Programming путешествия по Lua на Coddy — урок 17 из 70.
Вы видели, как __tostring управляет тем, как объект отображает себя. Другим полезным метаметодом является __eq, который определяет, когда два объекта должны считаться равными при использовании оператора ==.
По умолчанию, сравнение двух таблиц с помощью == проверяет, являются ли они одной и той же таблицей в памяти. Два отдельных объекта с идентичными данными вернут false:
local user1 = {id = 101, name = "Alice"}
local user2 = {id = 101, name = "Alice"}
print(user1 == user2) -- Вывод: false (разные таблицы)С помощью __eq вы можете определить собственную логику равенства. В классе вы добавляете его точно так же, как и __tostring — в виде функции в таблице класса. Чтобы сравнение на равенство работало, оба объекта должны иметь одну и ту же метатаблицу:
local User = {}
User.__index = User
function User:new(id, name)
local instance = {}
setmetatable(instance, self)
instance.id = id
instance.name = name
return instance
end
function User:__eq(other)
return self.id == other.id
endТеперь два объекта User считаются равными, если они имеют одинаковый ID, независимо от других полей:
local u1 = User:new(101, "Alice")
local u2 = User:new(101, "Bob")
local u3 = User:new(202, "Alice")
print(u1 == u2) -- Вывод: true (одинаковые ID)
print(u1 == u3) -- Вывод: false (разные ID)Этот паттерн полезен в тех случаях, когда объекты представляют сущности реального мира с уникальными идентификаторами — при сравнении записей базы данных, игровых сущностей или любых объектов, для которых идентичность важнее, чем адрес в памяти.
Задание
ЛегкоДавайте создадим класс Product, который может определять, являются ли два продукта одним и тем же товаром — даже если они хранятся в совершенно разных таблицах! В розничных системах товары часто имеют уникальные коды SKU (Stock Keeping Units), и два товара должны считаться равными, если у них одинаковый SKU, независимо от других деталей, таких как изменение цены.
Вы организуете свой код в двух файлах:
Product.lua: Определите классProduct, используя стандартный паттерн прототипа. Каждый продукт должен хранитьsku(уникальный идентификатор) иname. Реализуйте метаметод__eqтак, чтобы два продукта считались равными, если у них одинаковый SKU — имя не имеет значения для равенства.main.lua: Подключите модуль Product и создайте несколько экземпляров продукта. Сравните их с помощью оператора==, чтобы увидеть вашу пользовательскую логику равенства в действии.
Ваш класс Product должен включать:
- Конструктор
:new(sku, name) - Метод
:getInfo(), который возвращает строку в формате:[sku]: [name] - Метаметод
__eq, который сравнивает продукты по их SKU
Вы получите шесть входных данных:
- SKU для первого продукта
- Имя для первого продукта
- SKU для второго продукта
- Имя для второго продукта
- SKU для третьего продукта
- Имя для третьего продукта
В основном файле создайте три продукта, используя предоставленные входные данные, а затем выведите:
- Информацию о каждом продукте (три строки)
- Результат сравнения продукта 1 с продуктом 2
- Результат сравнения продукта 1 с продуктом 3
Например, если входные данные: ABC123, Wireless Mouse, ABC123, Mouse (Updated), XYZ789 и Keyboard, вывод должен быть следующим:
ABC123: Wireless Mouse
ABC123: Mouse (Updated)
XYZ789: Keyboard
true
falseОбратите внимание, что первые два продукта равны (одинаковый SKU), хотя их имена различаются — именно так реальные системы инвентаризации отслеживают товары при изменении названий и обновлениях!
Шпаргалка
Метаметод __eq определяет пользовательскую логику равенства для объектов, использующих оператор ==.
По умолчанию сравнение двух таблиц проверяет, являются ли они одной и той же таблицей в памяти:
local user1 = {id = 101, name = "Alice"}
local user2 = {id = 101, name = "Alice"}
print(user1 == user2) -- Output: false (different tables)Чтобы определить пользовательское равенство, добавьте __eq как функцию в таблицу класса. Оба объекта должны иметь одну и ту же метатаблицу:
local User = {}
User.__index = User
function User:new(id, name)
local instance = {}
setmetatable(instance, self)
instance.id = id
instance.name = name
return instance
end
function User:__eq(other)
return self.id == other.id
endТеперь объекты равны на основе вашей пользовательской логики:
local u1 = User:new(101, "Alice")
local u2 = User:new(101, "Bob")
local u3 = User:new(202, "Alice")
print(u1 == u2) -- Output: true (same ID)
print(u1 == u3) -- Output: false (different IDs)Попробуйте сами
-- Подключить модуль Product
local Product = require('Product')
-- Прочитать входные данные
local sku1 = io.read()
local name1 = io.read()
local sku2 = io.read()
local name2 = io.read()
local sku3 = io.read()
local name3 = io.read()
-- TODO: Создать три экземпляра Product, используя входные данные
-- TODO: Вывести информацию о каждом продукте (три строки)
-- TODO: Вывести результат сравнения продукта 1 с продуктом 2
-- TODO: Вывести результат сравнения продукта 1 с продуктом 3
В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Object Oriented Programming
1Концепция 'self'
Таблицы с функциямиЯвный 'self'Синтаксис с двоеточиемТочка против двоеточияИтоги — Движущаяся точка4Проект: Цифровой банк
Настройка проектаМетод пополнения7Полиморфизм и переопределение
Переопределение методовВызов родительских методовУтиная типизацияОбщий интерфейсПроверка типаИтоги — Роли сотрудников2Паттерн прототипа класса
Концепция прототипаСвязывание через __indexКонструктор :new()Инициализация атрибутовНезависимые экземплярыИтоги — Автозавод5Перегрузка операторов в ООП
Сложение объектовВычитание объектовКонкатенация объектовСравнение объектов (<, >)Повторение — Математика кошелька8Инкапсуляция
Соглашения об именованииЗамыкания для приватностиДоступ через замыканияТаблицы только для чтенияЛогика валидацииИтоги — Защищенное хранилище11Паттерны проектирования (Lite)
Фабричные функцииТаблица SingletonПаттерн IteratorObserver (Слушатель)Итоги — Logger Factory3Состояние и поведение объектов
Переменные экземпляраГеттерыСеттерыВычисляемые свойстваФорматирование строкПроверка на равенствоПовторение — Оценка студента6Основы наследования
Настройка наследованияНаследование методовРасширение конструктораДобавление дочерних методовОбщее и уникальноеИтоги: Иерархия фигур