この第1版はLua 5.0向けに執筆されました。後続のバージョンでも大部分は関連性がありますが、いくつかの相違があります。
第4版はLua 5.3を対象にしています。Amazonおよび他の書店で購入できます。
書籍を購入することで、Luaプロジェクトのサポートにもつながります。
![]() |
Programming inLua | ![]() |
第2部 テーブルとオブジェクト 第13章 メタテーブルとメタメソッド |
このセクションでは、メタテーブルの使い方を説明するためにシンプルな例を紹介します。集合を表すのにテーブルを使用し、2つの集合の和、交差などの計算を行う関数を想定します。リストの場合と同様に、これらの関数をテーブル内に格納し、新しい集合を作成するコンストラクターを定義します
Set = {} function Set.new (t) local set = {} for _, l in ipairs(t) do set[l] = true end return set end function Set.union (a,b) local res = Set.new{} for k in pairs(a) do res[k] = true end for k in pairs(b) do res[k] = true end return res end function Set.intersection (a,b) local res = Set.new{} for k in pairs(a) do res[k] = b[k] end return res end例を確認するために、集合を出力する関数も定義します
function Set.tostring (set) local s = "{" local sep = "" for e in pairs(set) do s = s .. sep .. e sep = ", " end return s .. "}" end function Set.print (s) print(Set.tostring(s)) end
さて、加算演算子 (`+
´) を使用して2つの集合の和を計算できるようにしたいとします。そのためには、集合を表すすべてのテーブルがメタテーブルを共有し、このメタテーブルが加算演算子への反応方法を定義します。最初の手順として、集合のメタテーブルとして使用する通常のテーブルを作成します。名前空間が汚れないように、Set
テーブルに格納します
Set.mt = {} -- metatable for sets次の手順として、集合を作成する
Set.new
関数を変更します。新しいバージョンには追加の行が1つだけあり、作成するテーブルのメタテーブルとしてmt
を設定しますfunction Set.new (t) -- 2nd version local set = {} setmetatable(set, Set.mt) for _, l in ipairs(t) do set[l] = true end return set endこれ以降、
Set.new
を使用して作成するすべての集合には、そのメタテーブルとして同じテーブルが設定されますs1 = Set.new{10, 20, 30, 50} s2 = Set.new{30, 1} print(getmetatable(s1)) --> table: 00672B60 print(getmetatable(s2)) --> table: 00672B60
最後に、メタテーブルにいわゆるメタメソッドを追加します。これは、和の計算方法を表すフィールド__add
です
Set.mt.__add = Set.unionLuaが2つの集合を加算しようとするたびに、この関数が引数として2つのオペランドを使用して呼び出されます。
メタメソッドが設定されたら、加算演算子を使用して集合の和を求めることができます
s3 = s1 + s2 Set.print(s3) --> {1, 10, 20, 30, 50}同様に、乗算演算子を使用して集合の交差を求めることができます
Set.mt.__mul = Set.intersection Set.print((s1 + s2)*s1) --> {10, 20, 30, 50}
各算術演算子には、メタテーブル内の対応するフィールド名があります。__add
と__mul
のほかに、__sub
(減算)、__div
(除算)、__unm
(否定)、および__pow
(べき乗)があります。連結演算子の動作を定義するフィールド__concat
を定義することもできます。
2つの集合を加算するときは、使用するメタテーブルに疑問はありません。ただし、2つの異なるメタテーブルを持つ2つの値を混在させる式を記述する場合があります。例えば、次のようにです
s = Set.new{1,2,3} s = s + 8メタメソッドを選択するために、Luaは次のようにします。(1) 最初の値のメタテーブルに
__add
フィールドがある場合、Luaはこの値をメタメソッドとして使用し、2番目の値には依存しません。(2) そうでない場合、2番目の値のメタテーブルに__add
フィールドがある場合、Luaはこの値をメタメソッドとして使用します。(3) そうでない場合、Luaはエラーを発生させます。したがって、最後の例ではSet.union
が呼び出され、式10 + s
と"hy" + s
でも同様に呼び出されます。Luaはこれらの混在型を気にしませんが、実装は気になります。s = s + 8
の例を実行すると、Set.union
内でエラーが発生します
bad argument #1 to `pairs' (table expected, got number)よりわかりやすいエラーメッセージを表示したい場合は、操作を実行する前にオペランドの型を明示的にチェックする必要があります
function Set.union (a,b) if getmetatable(a) ~= Set.mt or getmetatable(b) ~= Set.mt then error("attempt to `add' a set with a non-set value", 2) end ... -- same as before
Copyright © 2003–2004 Roberto Ierusalimschy. All rights reserved. | ![]() |