等価性のチェック
CoddyのLuaジャーニー「Object Oriented Programming」セクションの一部 — レッスン 17/70。
__tostring がオブジェクトの表示方法をどのように制御するかを見てきました。もう一つの便利なメタメソッドは __eq で、これは == 演算子を使用して2つのオブジェクトがいつ等しいと見なされるべきかを定義します。
デフォルトでは、== を使用して2つのテーブルを比較すると、それらがメモリ内のまったく同じテーブルであるかどうかがチェックされます。同一のデータを持つ2つの別々のオブジェクトは 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これで、他のフィールドの内容にかかわらず、同じIDを共有していれば2つのUserオブジェクトは等価であるとみなされます:
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)このパターンは、オブジェクトが一意の識別子を持つ現実世界のエンティティを表す場合に有用です。データベースのレコードやゲームのエンティティの比較、あるいはメモリ上の場所よりもアイデンティティ(同一性)が重要となるあらゆるオブジェクトにおいて価値を発揮します。
チャレンジ
簡単2つの製品が、たとえ全く異なるテーブルに保存されていても、同じアイテムであるかどうかを判断できる Product クラスを作成しましょう。小売システムでは、製品は通常、一意のSKUコード(Stock Keeping Units)を持っており、価格の変更などの他の詳細に関係なく、同じSKUを共有していれば2つの製品は等しいと見なされるべきです。
コードは2つのファイルに分けて構成します:
Product.lua: 標準的なプロトタイプパターンを使用してProductクラスを定義します。各製品はsku(一意の識別子)とnameを保持する必要があります。2つの製品が同じSKUを持っている場合に等しいと見なされるように__eqメタメソッドを実装してください。等価性の判定において名前は関係ありません。main.lua: Productモジュールをrequireし、いくつかの製品インスタンスを作成します。==演算子を使用してそれらを比較し、カスタムの等価ロジックが動作することを確認してください。
Product クラスには以下を含める必要があります:
:new(sku, name)コンストラクタ[sku]: [name]という形式の文字列を返す:getInfo()メソッド- SKUによって製品を比較する
__eqメタメソッド
6つの入力を受け取ります:
- 1番目の製品のSKU
- 1番目の製品の名前
- 2番目の製品のSKU
- 2番目の製品の名前
- 3番目の製品のSKU
- 3番目の製品の名前
メインファイルで、提供された入力を使用して3つの製品を作成し、以下を出力してください:
- 各製品の情報(3行)
- 製品1と製品2を比較した結果
- 製品1と製品3を比較した結果
例えば、入力が ABC123, Wireless Mouse, ABC123, Mouse (Updated), XYZ789, Keyboard の場合、出力は以下のようになります:
ABC123: Wireless Mouse
ABC123: Mouse (Updated)
XYZ789: Keyboard
true
false名前が異なっていても、最初の2つの製品が等しい(同じSKU)と見なされていることに注目してください。これは、実際の在庫システムが名前の変更や更新を通じて製品を追跡する方法そのものです!
チートシート
__eq メタメソッドは、== 演算子を使用したオブジェクトのカスタム等価ロジックを定義します。
デフォルトでは、2つのテーブルを比較すると、それらがメモリ上の同じテーブルであるかどうかがチェックされます。
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: 入力を使用して3つのProductインスタンスを作成する
-- TODO: 各製品の情報を表示する(3行)
-- TODO: 製品1と製品2の比較結果を表示する
-- TODO: 製品1と製品3の比較結果を表示する
このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。