1. ホーム
  2. スクリプト・コラム
  3. ルア

Luaのメタテーブルの概念を説明する

2022-02-10 04:49:53

 メタテーブルは、接続するキーセットと、その下にあるヘルパーテーブルの関連メタメソッドの動作を変更するのに役立つテーブルです。これらのメタ・メソッドは、以下のような強力なluaの機能です。

  •     演算子テーブルの変更・関数追加
  •     インデックス・メタ・テーブルを使用して、テーブルにキーがない場合にメタ・テーブルを表示する。

メタテーブルの処理には、次の2つの重要な方法があることが示されています。

  •     setmetatable(table,metatable)。このメソッドは、メタデータにテーブルを設定するために使用されます。
  •     getmetatable(table): このメソッドは、テーブルのメタデータを取得するために使用されます。

まず、テーブルを別のメタデータとして設定する方法から見ていきましょう。それは以下のようになります。

コピーコード コードは以下の通りです。
mytable = {}
mymetatable = {}
setmetatable(mytable,mymetatable)

上記のコードを1行で表すと、次のようになります。

コピーコード コードは以下の通りです。
mytable = setmetatable({},{})

__index

テーブルのルックアップ・メタ・テーブルで提供されない場合の簡単な例を以下に示します。

コピーコード コードは以下の通りです。
mytable = setmetatable({key1 = "value1"}, {
  __index = function(mytable, key)
    if key == "key2" then
      return "metatablevalue"
    else
      return mytable[key]
    end
  end
})

print(mytable.key1,mytable.key2)

上記のプログラムを実行すると、次のような出力が得られます。

コピーコード コードは以下の通りです。
value1 metatablevalue

上の例の手順で、何が起こったかを説明しましょう。

  •     ここでテーブルmytableは{key1 = "value1"}です。
  •     メタテーブルには、メタメソッドと呼んでいるmytable内の関数__indexが設定されています。
  •     meta メソッドは、インデックス "key2" を調べて、見つかれば "metatablevalue" を返し、そうでなければ対応する mytable インデックスの値を返すという簡単な仕事をします。

上記のプログラムを簡略化すると、次のようになる。


コピーコード コードは以下の通りです。
mytable = setmetatable({ key1 = "value1"}, { __index = { key2 = "metatablevalue" } })
print(mytable.key1,mytable.key2)

__newindex

メタテーブルに __newindex を追加したとき、そのキーがテーブル内にない場合は、新しいキーの動作はリレーメソッドで定義されます。主テーブルにインデックスがない場合のメタテーブルのインデックスを設定する簡単な例は、次のようになります。

コピーコード コードは以下の通りです。
mymetatable = {}
mytable = setmetatable({key1 = "value1"}, { __newindex = mymetatable })

print(mytable.key1)

mytable.newkey = "new value 2"
print(mytable.newkey,mymetatable.newkey)

mytable.key1 = "new value 1"
print(mytable.key1,mymetatable.newkey1)

上記のプログラムを実行すると、次のような出力が得られます。

コピーコード コードは以下の通りです。
value1
nil new value 2
new value 1 nil

上のプログラムを見ればわかるように、メインテーブルにキーが存在する場合は、それを更新するだけです。メインテーブルにキーがない場合は、キーメタレートを追加しています。

また、同じテーブルに対して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"

rawsetはメタテーブル__newindexを使わずに値を設定します。同じようにrawgetも__indexを使わずに値を取得します。
テーブル結合演算子の動作について

2つのテーブルを+演算子で結合する簡単な例を以下に示します。

コピーコード コードは以下の通りです。
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 キーには、メタテーブルへの追加演算子 + 動作が含まれています。テーブルのキーと対応する演算子は以下の通りです。

 __call

__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

print文の動作を変更するには、__toStringメタメソッドを使用します。簡単な例を以下に示します。

コピーコード コードは以下の通りです。
mytable = setmetatable({ 10, 20, 30 }, {
  __tostring = function(mytable)
    sum = 0
    for k, v in pairs(mytable) do
  sum = sum + v
 end
    return "The sum of values in the table is " . sum
  end
})
print(mytable)

上記のプログラムを実行すると、次のような出力が得られます。

コピーコード コードは以下の通りです。
The sum of values in the table is 60

メタテーブルの機能が充実していることを知れば、使わなければ非常に煩雑になるような操作を、本当にたくさん行うことができるようになります。ですから、解釈のためのサンプルとしてさまざまなオプションを提供し、また自分自身のサンプルを作成するために、メタテーブルのメタテーブルを使った作業を行うようにしてください。