Menu
Coddy logo textTech

オブジェクトの加算

CoddyのLuaジャーニー「Object Oriented Programming」セクションの一部 — レッスン 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 はコロンではなくドットで定義されることに注意してください。これは両方のオペランドを引数として受け取り、元のいずれかを変更するのではなく、新しいオブジェクトを返す必要があります。これにより、操作の予測可能性と安全性が保たれます。

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 をメタテーブルとして設定しているため、それらはすべて自動的にこの動作を共有します。

challenge icon

チャレンジ

簡単

+ 演算子を使用して加算をサポートする Vector クラスを作成しましょう。これは演算子オーバーロードへの第一歩です。演算子オーバーロードを使用することで、オブジェクトを Lua の組み込み演算子と自然に連携させることができます。

コードは 2 つのファイルに分けて構成します:

  • Vector.lua: xy コンポーネントを持つ Vector クラスを定義します。:new(x, y) コンストラクタを含め、2 つのベクトルを加算するとコンポーネントが合算された新しいベクトルが作成されるように __add メタメソッドを実装してください。__add は(コロン構文ではなく)ドット構文を使用し、両方のオペランドを引数として受け取ることに注意してください。
  • main.lua: Vector モジュールを require し、ベクトルのインスタンスを作成して、それらを加算すると正しい結果が得られることを示します。

4 つの入力を受け取ります:

  1. 1 つ目のベクトルの x コンポーネント
  2. 1 つ目のベクトルの y コンポーネント
  3. 2 つ目のベクトルの x コンポーネント
  4. 2 つ目のベクトルの y コンポーネント

メインファイルで、与えられたコンポーネントを使用して 2 つのベクトルを作成し、+ 演算子を使ってそれらを加算し、結果のベクトルの xy の値を別々の行に出力してください。

例えば、入力が 3, 4, 1, 2 の場合、出力は以下のようになります:

4
6

1 つ目のベクトル (3, 4) と 2 つ目のベクトル (1, 2) を足すと、新しいベクトル (4, 6) になります。

チートシート

__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 はコロンではなく、ドットで定義されます。これは両方のオペランドを引数として受け取り、元のいずれかを変更するのではなく、新しいオブジェクトを返す必要があります。

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モジュールを読み込む
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: 入力値を使用して2つのVectorインスタンスを作成する

-- TODO: +演算子を使用して2つのベクトルを加算する

-- TODO: 結果のベクトルのx値とy値を別々の行に出力する
quiz icon腕試し

このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。

Object Oriented Programmingのすべてのレッスン