Menu
Coddy logo textTech

Проверка на равенство

Часть раздела 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)

Этот паттерн полезен в тех случаях, когда объекты представляют сущности реального мира с уникальными идентификаторами — при сравнении записей базы данных, игровых сущностей или любых объектов, для которых идентичность важнее, чем адрес в памяти.

challenge icon

Задание

Легко

Давайте создадим класс 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

Вы получите шесть входных данных:

  1. SKU для первого продукта
  2. Имя для первого продукта
  3. SKU для второго продукта
  4. Имя для второго продукта
  5. SKU для третьего продукта
  6. Имя для третьего продукта

В основном файле создайте три продукта, используя предоставленные входные данные, а затем выведите:

  1. Информацию о каждом продукте (три строки)
  2. Результат сравнения продукта 1 с продуктом 2
  3. Результат сравнения продукта 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
quiz iconПроверьте себя

В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.

Все уроки раздела Object Oriented Programming