Luaでクラスのような実装をする(テーブル+メタテーブル)

目次

概要

Luaには他言語のようなクラスという仕組みはありませんが、テーブルとメタテーブル(__index)を使うことで、クラスのような構造を実装できます。

 

ポイント

  • Luaにはクラスはありません
  • テーブル+メタテーブルでクラス風に実装する
  • __indexでメソッド探索を行う
  • インスタンスはsetmetatableで作る

 

メタテーブルとは

テーブルの動作をカスタマイズするための設定テーブルです。

 

通常のテーブル

local t = {}
print(t.x)  -- nil(存在しないキーはnil)

そのまま値を返します。通常のテーブルは決まった動作しかしません。

 

メタテーブルを使う

local t = {}
local mt = { __index = function() return 0 end }
setmetatable(t, mt)

print(t.x)  -- 0(存在しないキーでも0を返す)

setmetatable(t, mt)のmtがメタテーブルです。

メタテーブルを設定すると、その動作を変えられます。

以下のイメージです。

このテーブルで○○が起きたときは、この設定に従って動かしてください

クラス風の基本実装

local Color = {} -- テーブル
Color.__index = Color -- __indexを設定

function Color:new(name)
    local obj = setmetatable({ name = name }, Color) -- Colorがメタテーブル
    return obj
end

function Color:getName()
    return self.name
end

-- 使用例
local c1 = Color:new("red")
print(c1:getName()) -- red

local c2 = Color:new("blue")
print(c2:getName()) -- blue

 

解説

① クラステーブル

local Color = {}
Color.__index = Color

Colorはクラスのような役割です。
__indexに自分自身を設定することで、メソッド探索先になります。

 

②インスタンス生成

local obj = setmetatable({ name = name }, Color)

name=nameはテーブルのキーのnameに、引数nameの値を入れているという意味です。
以下のテーブルが作成されます。

obj = {
    name = "red"
}

 

Colorは、メタテーブルです。
メタテーブルのColorの__index=Colorにより、Color.getNameが見つかりobjからColorのメソッドを使えるようになります。

obj
├── name = "red" ← 自分自身のデータ
└── (メタテーブル = Color)
     └── getName ← ここから借りてくる

 

③ メソッド定義

function Color:getName()
    return self.name
end

:記法によりselfが自動で渡されます。
インスタンスのデータにアクセス可能です。

 

__index の動作

c:getName()

このとき内部では、

1.c.getNameを探す→存在しない
2.メタテーブルColor.__indexを見る
3.Color.getNameを見つけて呼び出す

これによりインスタンスからメソッドが呼べます。

 

なぜ __indexを外で定義するのか

Color.__index = Color

これを new() の中ではなく、外に書く理由:

  • 毎回設定する必要がない
  • クラス定義として明確になる
  • 可読性が高い

関連の記事

Lua (__index) 存在しないキー参照時の動作
Luaで継承のような実装をする(テーブル+メタテーブル)

△上に戻る