Lua メタテーブル
Lua テーブルでは、対応するキーにアクセスして値を取得できますが、2 つのテーブルを操作することはできません。
そのため、Lua はテーブルの動作を変更できるメタテーブル (Metatable) を提供しており、各動作は対応するメタメソッドに関連付けられています。
たとえば、メタテーブルを使用して、Lua が 2 つのテーブルの加算演算 a+b を計算する方法を定義できます。
Lua が 2 つのテーブルを追加しようとすると、最初に 2 つのテーブルのいずれかにメタテーブルがあるかどうかを確認し、次に「__add」というフィールドがあるかどうかを確認します。見つかった場合は、対応する値が呼び出されます。 「__add」などのリアルタイム フィールドの場合、対応する値 (多くの場合、関数またはテーブル) は「メタメソッド」です。
メタテーブルを処理するための非常に重要な関数が 2 つあります:
setmetatable(table, metatable): 指定されたテーブルにメタテーブル (metatable) を設定します。メタテーブル (metatable) に __metatable キー値が存在する場合、setmetatable を実行します。失敗します。
getmetatable(table): オブジェクトのメタテーブルを返します。
次の例は、指定されたテーブルのメタテーブルを設定する方法を示しています:
mytable = {} -- 普通表 mymetatable = {} -- 元表 setmetatable(mytable,mymetatable) -- 把 mymetatable 设为 mytable 的元表
上記のコードは 1 行で直接記述することもできます:
mytable = setmetatable({},{})
以下は、返されるオブジェクト メタテーブルです:
getmetatable(mytable) -- 这回返回mymetatable
__index metaメソッド
これはメタテーブルであり、最も一般的に使用されるキーです。
キーによってテーブルにアクセスするとき、キーに値がない場合、Lua はテーブルのメタテーブル内で __index キーを検索します (メタテーブルがあると仮定して)。 __index にテーブルが含まれている場合、Lua はテーブル内で対応するキーを検索します。lua コマンドを使用して対話モードに入り、表示することができます:
$ lua Lua 5.3.0 Copyright (C) 1994-2015 Lua.org, PUC-Rio > other = { foo = 3 } > t = setmetatable({}, { __index = other }) > t.foo 3 > t.bar nil
__index に関数が含まれている場合、Lua はその関数を呼び出し、テーブルとキーがパラメーターとして関数に渡されます。
__index メタ メソッドは、要素がテーブルに存在するかどうかを確認し、存在しない場合は結果を nil に返します。
mytable = setmetatable({key1 = "value1"}, { __index = function(mytable, key) if key == "key2" then return "metatablevalue" else return nil end end }) print(mytable.key1,mytable.key2)
インスタンスの出力結果は:
value1 metatablevalue
インスタンス分析:
mytableテーブルの割り当ては{key1 = "value1"}です。
mytable はメタテーブルを設定し、メタメソッドは __index です。
mytable テーブルで key1 を探します。見つかった場合は要素を返します。見つからない場合は続行します。
mytable テーブルで key2 を探します。見つかった場合は、metatablevalue を返します。見つからない場合は、続行します。
メタテーブルに __index メソッドがあるかどうかを確認します。__index メソッドが関数である場合は、その関数を呼び出します。
メタメソッドで、「key2」キーパラメータが渡されているかどうかを確認します(mytable.key2が設定されています)。「key2」パラメータが渡された場合は「metatablevalue」が返され、それ以外の場合は対応するキー値が返されます。 mytable に返されます。
上記のコードは次のように簡単に書くことができます:
mytable = setmetatable({key1 = "value1"}, { __index = { key2 = "metatablevalue" } }) print(mytable.key1,mytable.key2)
概要
Lua でテーブル要素を見つけるためのルールは、実際には次の 3 つのステップです:
1.見つかった場合は要素を返し、見つからない場合は続行します
2. テーブルにメタテーブルがあるかどうかを判断します。メタテーブルがない場合は、nil を返します。
3. メタテーブルに __index メソッドがあるかどうかを判断します。__index メソッドが nil の場合は nil を返し、__index メソッドが関数の場合は 1、2、3 を繰り返します。この関数の戻り値。
__newindex メタメソッド
__newindex メタメソッドはテーブルの更新に使用され、__index はテーブルにアクセスするために使用されます。
テーブルの欠落しているインデックスに値を割り当てると、インタープリターは __newindex メタメソッドを探します。存在する場合は、割り当てを実行せずにこの関数を呼び出します。
次の例は、__newindex メタメソッドの適用を示しています:
mymetatable = {} mytable = setmetatable({key1 = "value1"}, { __newindex = mymetatable }) print(mytable.key1) mytable.newkey = "新值2" print(mytable.newkey,mymetatable.newkey) mytable.key1 = "新值1" print(mytable.key1,mymetatable.key1)
上記の例の実行出力は次のとおりです:
value1 nil 新值2 新值1 nil
上記の例では、テーブルは、値を代入するときにメタメソッド __newindex を設定します。新しいインデックス キー (newkey) (mytable.newkey = "新しい値 2") の場合、値を割り当てずにメタ メソッドが呼び出されます。既存のインデックス キー (key1) が割り当てられている場合、メタ メソッド __newindex を呼び出さずに値が割り当てられます。
次の例では、rawset 関数を使用してテーブルを更新します:
mytable = setmetatable({key1 = "value1"}, { __newindex = function(mytable, key, value) rawset(mytable, key, "\""..value.."\"") end }) mytable.key1 = "new value" mytable.key2 = 4 print(mytable.key1,mytable.key2)
上記の例の実行出力は次のとおりです:
new value "4"
演算子をテーブルに追加します
次の例は、2 つのテーブルの加算操作を示しています:
-- 计算表中最大值,table.maxn在Lua5.2以上版本中已无法使用 -- 自定义计算表中最大值函数 table_maxn function table_maxn(t) local mn = 0 for k, v in pairs(t) do if mn < k then mn = k end end return mn end -- 两表相加操作 mytable = setmetatable({ 1, 2, 3 }, { __add = function(mytable, newtable) for i = 1, table_maxn(newtable) do table.insert(mytable, table_maxn(mytable)+1,newtable[i]) end return mytable end }) secondtable = {4,5,6} mytable = mytable + secondtable for k,v in ipairs(mytable) do print(k,v) end
上記の実行例の出力 結果は次のとおりです:
1 1 2 2 3 3 4 4 5 5 6 6
__add キーはメタテーブルに含まれており、追加操作が実行されます。 表内の対応する演算リストは次のとおりです:
モード | 説明 |
---|---|
__add | 対応する演算子 '+'. |
__sub | 対応する演算子 '-'. |
__mul | は演算子 '*' に対応します。 |
__div | は演算子 '/' に対応します。 |
__mod | は演算子 '%' に対応します。うーん |
__concat | |
__eq | |
__lt | |
__le | |
-- 计算表中最大值,table.maxn在Lua5.2以上版本中已无法使用 -- 自定义计算表中最大值函数 table_maxn function table_maxn(t) local mn = 0 for k, v in pairs(t) do if mn < k then mn = k end end return mn end -- 定义元方法__call mytable = setmetatable({10}, { __call = function(mytable, newtable) sum = 0 for i = 1, table_maxn(mytable) do sum = sum + mytable[i] end for i = 1, table_maxn(newtable) do sum = sum + newtable[i] end return sum end }) newtable = {10,20,30} print(mytable(newtable))
上記の例の出力結果は次のとおりです。
70__tostring Metamethod__tostring メタメソッドは、テーブルの出力動作を変更するために使用されます。次の例では、テーブルの出力内容をカスタマイズしました:
mytable = setmetatable({ 10, 20, 30 }, { __tostring = function(mytable) sum = 0 for k, v in pairs(mytable) do sum = sum + v end return "表所有元素的和为 " .. sum end }) print(mytable)
上記の例の実行の出力結果は次のとおりです:
表所有元素的和为 60
この記事から、メタテーブルはコード関数を非常に単純化できることがわかります。 Lua のメタテーブルを理解すると、よりシンプルで優れた Lua コードを書いてみましょう。