オブジェクトの加算
CoddyのLuaジャーニー「オブジェクト指向プログラミング」セクションの一部。レッスン 26/70。
__tostringや__eqのようなメタメソッドを使うと、オブジェクトの振る舞いをカスタマイズできることはすでに見てきました。次はこれを算術演算にも広げ、加算から始めます。
__addメタメソッドは、2つのオブジェクト間で+演算子を使ったときに何が起こるかを定義します。Luaはa + bを見ると、どちらかのオペランドのメタテーブルで__addを探します。
local Vector = {}
Vector.__index = Vector
function Vector:new(x, y)
local obj = {x = x, y = y}
setmetatable(obj, Vector)
return obj
end
function Vector.__add(v1, v2)
return Vector:new(v1.x + v2.x, v1.y + v2.y)
end__addがドットで定義されていることに注目してください。Luaでは両方のオペランドが通常の引数として渡され、ドット形式ではその両方に名前を付けます。コロンを使っても動作します。function Vector:__add(other)はfunction Vector.__add(self, other)と同じですが、ドット形式が慣例です。__addは、元のどちらかを変更するのではなく、新しいオブジェクトを返すべきです。これにより、操作の予測可能性と安全性が保たれます。
local a = Vector:new(3, 4)
local b = Vector:new(1, 2)
local c = a + b
print(c.x, c.y) -- 出力: 4 6重要なポイントは、__addはオブジェクトだけでなく、メタテーブル自体(ここではVector)に置く必要があるということです。すべてのインスタンスのメタテーブルとしてVectorを設定しているため、すべてのインスタンスがこの動作を自動的に共有します。
チャレンジ
簡単Vectorクラスを作り、+演算子を使った加算をサポートしましょう。これは演算子オーバーロードへの第一歩です。オブジェクトがLuaの組み込み演算子と自然に連携できるようにします。
コードを2つのファイルに分けて記述します。
Vector.lua:xとyの成分を持つVectorクラスを定義します。:new(x, y)コンストラクターを用意し、2つのベクトルを加算すると、成分を合成した新しいベクトルが作られるように__addメタメソッドを実装します。__addはドット構文で定義し、両方のオペランドを名前付き引数として受け取るようにします。main.lua: Vectorモジュールを読み込み、ベクトルのインスタンスを作成して、それらを加算すると正しい結果が得られることを示します。
入力は4つ与えられます。
- 最初のベクトルのx成分
- 最初のベクトルのy成分
- 2番目のベクトルのx成分
- 2番目のベクトルのy成分
メインファイルで、与えられた成分を使って2つのベクトルを作成し、+演算子で加算して、結果のベクトルのxとyの値を別々の行に出力してください。
たとえば、入力が3、4、1、2の場合、出力は次のようになります。
4
6最初のベクトル(3, 4)に2番目のベクトル(1, 2)を加算すると、新しいベクトル(4, 6)になります。
自分で試してみよう
-- Vector モジュールを読み込む
local Vector = require('Vector')
-- 入力を読み取る
local x1 = tonumber(io.read())
local y1 = tonumber(io.read())
local x2 = tonumber(io.read())
local y2 = tonumber(io.read())
-- TODO: 入力値を使って Vector のインスタンスを2つ作成する
-- TODO: + 演算子を使って2つのベクトルを加算する
-- TODO: 計算結果のベクトルの x と y の値をそれぞれ別の行に出力する
このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。
オブジェクト指向プログラミングのすべてのレッスン
自分で練習してみよう: Luaオンラインコンパイラ