目次
概要
Luaの__indexは、テーブルに存在しないキーを参照したときの動作を定義するメタメソッドです。
通常、テーブルtに対してt[key]を実行した場合、以下になりますが
- キーが存在する→その値を返す
- キーが存在しない→nilを返す
メタテーブルに__indexを設定すると、キーが見つからなかった場合のフォールバック処理を定義できます。
主な用途
- デフォルト値の提供
- 継承(プロトタイプ)
__index に関数を設定した場合
基本の動き
local t = {}
print(t.x) -- nil
キーxが存在しないためnilが返ります。
__index に関数を設定した場合
local t = {}
local mt = {
__index = function(tbl, key)
return "'" .. key .. "' does not exist"
end
}
setmetatable(t, mt)
print(t.a) -- 'a' does not exist
11行目のt.aは存在しないキーです。
そのため__indexが呼ばれ、カスタムのエラーメッセージを返します。
__index にテーブルを設定する(デフォルト値 / 継承)
__index には関数だけでなく、テーブルも指定可能です。
local defaults = {
a = "red",
b = "green"
}
local t = {}
setmetatable(t, {
__index = defaults
})
print(t.a) -- red
print(t.b) -- green
12,13行目のtに、aやbは存在しません。
9行目は、__index=defaultsのためdefaults.a,defaults.bが参照されます。
チェーン(連鎖)
__index 先のテーブルにもメタテーブルがある場合に再帰的に検索されます。
local t3 = { x = 100 }
local t2 = {}
setmetatable(t2, { __index = t3 })
local t1 = {}
setmetatable(t1, { __index = t2 })
print(t1.x) -- 100
キーが見つからないので、t1→t2→t3と検索しました。
注意点:無限ループの可能性
setmetatable(t1, { __index = t2 })
setmetatable(t2, { __index = t1 }) -- 危険
循環参照になると無限に探し続けるので注意します。
キーが存在し、__indexにも同じキーがある場合
local t = { a = 100 }
local defaults = { a = "red", b = "green" }
setmetatable(t, { __index = defaults })
print(t.a) -- 100(t側が優先)
print(t.b) -- green(存在しないのでdefaults)
1行目、2行目ともにキーのaが存在します。
この場合、テーブル自身の値(tのキー)が優先されます。
rawgetとは(メタテーブルを無視して純粋な値を取得する)
rawgetは、テーブルからメタテーブルを無視して値を取得する関数です。
local t = {}
setmetatable(t, {
__index = function()
return "default"
end
})
print(t.x) -- default
print(rawget(t, "x")) -- nil
9行目は、__indexが呼ばれています。
10行目は、__indexは呼ばれず、キーがないのでnilになります。
rawgetの利点
__index による見かけの値を排除できます。
デバッグで使えます。
関連の記事
