English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية

Lua メタテーブル(Metatable)

Luaのテーブルでは、対応するキーを通じてアクセスして値を取得できますが、二つのテーブルに対して操作を行うことはできません。

したがって、Lua はメタテーブル(Metatable)を提供し、テーブルの動作を変更することができます。各動作には対応するメタメソッドが関連付けられます。

例えば、元テーブルを使用して、Lua がテーブルの足し算操作 a をどのように計算するかを定義できます。+b。

Lua が二つのテーブルを足し算に試みるとき、まずその二つのテーブルのうちの一つにメタテーブルがあるかをチェックし、その後 ' __add ' というフィールドがあるかをチェックします。' __add ' などの即時フィールドは、対応する値(通常は関数またはテーブル)が ' メタメソッド ' です。

メタテーブルを処理するために非常に重要な二つの関数があります:

  • setmetatable(table, metatable): 指定されたテーブルにメタテーブル(metatable)を設定する際、メタテーブル(metatable)に __metatable キー値がある場合、setmetatable は失敗します。

  • getmetatable(table): オブジェクトのメタテーブル(metatable)を返します。

以下の例では、指定されたテーブルにメタテーブルを設定する方法を示します:

mytable = {}                          -- 通常のテーブル 
mymetatable = {}                      -- メタテーブル
setmetatable(mytable, mymetatable)     -- mymetatable を mytable のメタテーブルに設定します

上記のコードは一行で直接書けることもあります:

mytable = setmetatable({}, {})

以下は返されるオブジェクトのメタテーブルです:

getmetatable(mytable)                 -- これは mymetatable を返します。

__index 元方法

これは metatable で最もよく使われるキーです。

テーブルにキーを通じてアクセスする際、そのキーに値がなく、Lua はテーブルの metatable(存在する場合を仮定)の __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 を返します。存在する場合は __index が結果を返します。

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 メソッドが関数であれば、その関数を呼び出します。

  • メタテーブル内で「key」2「キーのパラメータ(mytable.key2設定済み(已設定),「key」2「パラメータが「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;__index メソッドが関数の場合、その関数の返値を返します。

この部分の内容は作者の環子から提供されています:https://blog.csdn.net/xocoder/article/details/9028347

__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"

テーブルに演算子を追加する

以下の例では、二つのテーブルの加算操作を示しています:

-- テーブルの最大値を計算します、table.maxnはLuaで5.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対応する演算子 '%'。
__unm対応する演算子 '"'。-'.
__concat対応する演算子 '..'。
__eq対応する演算子 '=='。
__lt対応する演算子 '<'。
__le対応する演算子 '<='。

__call メソッド

__call メソッドは Lua で値を呼び出す際に呼び出されます。以下の例では、テーブルの要素の和を計算する方法を示しています:

-- テーブルの最大値を計算します、table.maxnはLuaで5.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 メタメソッド

__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コードを書くことができます。