Lua setmetatableでテーブルの振る舞いを変更する

目次

概要

Luaではテーブルにメタテーブル(metatable)を設定することで、参照や演算などの挙動をカスタマイズできます。

その代表例が__indexで、存在しないキーにアクセスしたときの動作を定義できます。

 

まとめると

  • setmetatableでテーブルにメタテーブルを設定できる
  • __indexを使うと存在しないキーの参照動作を変更できる
  • __indexは関数だけでなくテーブルも指定可能

存在しないキー参照時の動作を変更する

setmetatableを使用すると振る舞いを変える・動作を追加できます。

local color1 = {
    a = "red"
}

local mt = {
    __index = function(tbl, key)
        return "That key does not exist."
    end
}

setmetatable(color1, mt)

print(color1.a) -- red
print(color1.b) -- That key does not exist.

1行目のcolor1は通常のテーブルです。
5行目のmtはメタテーブルです。
11行目のsetmetatable(color1,mt)により、color1にメタテーブルを設定します。

14行目のcolor1.b のように存在しないキーを参照すると通常は nil が返りますが

__index が定義されているため、__index(tbl, key) が呼ばれ戻り値がそのまま参照結果になります。

 

setmetatable を使わない場合

local color1 = { a = "red" }

print(color1.a)  -- red
print(color1.b)  -- nil

存在しないキーは単純にnilを返します。これがデフォルトの挙動です。

__indexの重要ポイント

1. 関数だけでなくテーブルも指定できる

local default = { b = "blue" }

local color1 = { a = "red" }

setmetatable(color1, { __index = default })

print(color1.a)  -- red
print(color1.b)  -- blue

__index=テーブルの場合、存在しないキーはそのテーブルから参照されます。

 

2. 疑似オブジェクト指向(メソッド共有)に使う

local Dog = {}
Dog.__index = Dog

function Dog:speak()
    print("barks")
end

local dog = setmetatable({}, Dog)
dog:speak()  -- barks

1行目は、空のテーブルを作成しています。これをクラス(設計図)として使います。
2行目は、見つからないキーはDogを見に行くという意味です。

8行目は、インスタンス生成です。
{}→空のインスタンス
Dog→メタテーブルとして設定
これによりdogはDogを参照できるようになります。

流れ

1.9行目、dog.speakを探す→無い(dogは空テーブル)
2.メタテーブルの__indexを確認→Dogが設定されている
3.Dog.speakを探す→見つかる
4.Dog.speak(dog)として実行→barks(吠える)が出力される

 

3.__indexが呼ばれる条件

print(t.y)  -- yというキーは定義していない → __index が呼ばれる

__indexが呼ばれる条件は、テーブルにそのキーが見つからないときです。

関連の記事

Lua 関数からテーブルを参照する(self と : の使い方)

△上に戻る