blog

Luaのメタテーブル

メタテーブルとは\n\n具体的には、数値の足し算、引き算、掛け算、割り算、文字列の連結、関数の呼び出し、テーブルエントリへの値の代入など、Luaではあらゆるタイプの値にデフォルトの操作が用意されていま...

Jul 14, 2025 · 4 min. read
シェア

メタブルとは

具体的には、数値の加算、減算、乗算、除算、文字列の連結、関数の呼び出し、テーブル・エントリへの値の代入などです。 これらは全てデフォルトのロジックに従います。 たとえば、2 つのテーブルを加算する方法を定義できます。

最も簡単な例では、2つのテーブルの加算を再定義しています。 この例では、cの__addフィールドを書き換え、aのMetatableをcに設定しています。加算操作が実行されると、LuaはまずaにMetatableがあるかどうか、そしてそのMetatableに__addフィールドが存在するかどうかをチェックし、存在する場合はそれを呼び出し、そうでない場合はbの条件をチェックし、どちらも存在しない場合はデフォルトの加算操作を呼び出し、テーブルに__addフィールドが存在しない場合はそれを呼び出します。どちらも存在しない場合、デフォルトの加算演算が呼び出され、テーブルがデフォルトの加算演算を定義していない場合、エラーがスローされます。

     --つのテーブルを定義する&n  bsp;
a = {5, 6}   b = {7, 8}   
--cをメタテーブルとして使う   
c = {}   
--加算の再定義   
c.__a  dd = function(op1, op2)   
for _, item in ipairs(op2) do   
table.insert(op1, item)     終了   
return op1     終了   
--aのMetatableをcに設定する。   
setmetatable(a, c)   
--d現在はこのようになっている。{5,6,7,8}   d = a + b 

何が起こっているのかがわかったら、Metatableの具体的なプロパティを見てみましょう。

Metatableは不思議なものではなく、ただの古いテーブルです。Luaはテーブルのデータ構造内でこれらの操作を再定義するためのエントリーポイントをいくつか定義しています。 これらはすべて、テーブルのフィールドを表すダブルアンダースコア(上の例では__add)で始まります。 ある値に対してMetatableを設定し、Metatable内の対応する操作フィールドの書き換えを設定すると、その値が操作を実行したときに書き換えられたカスタム操作がトリガーされます。 例えば、__add は、プラス記号の両側にある 2 つのオペランドをパラメータとして渡し、戻り値を要求します。 この振る舞いをイベントに例える人もいます。xxの振る舞いがトリガーされると、イベントカスタムのアクションがトリガーされます。

Luaではどのような値もメタテーブルを持ち、異なる値は異なるメタテーブルを持つことも、同じメタテーブルを共有することもできますが、Lua自体が提供する機能では、C拡張や他のライブラリを使用しない限り、テーブル型以外の値のメタテーブルを変更することはできません。 setmetatableとgetmetatableは、テーブル型のMetatableを操作するためのメソッド群です。

メタテーブルとオブジェクト指向

Luaは手続き型言語ですが、メタテーブルを使ってオブジェクト指向をシミュレートすることができます。 その鍵となるのが__indexフィールドです。 これはテーブルのインデックス値へのアクセスを提供します。 テーブルがtable[key]のような値でインデックスされている場合、Luaはまずテーブル自体でkeyの値を調べ、もしそれがなく、__index属性を持つメタテーブルがあれば、__indexで定義された関数のロジックに従ってそれを調べます。 考えてみれば、これはオブジェクト指向の核心である継承を実装する方法です。 Luaでオブジェクト指向を実装する方法はたくさんありますが、__indexを使う方法はありません。

この例では、ProgrammingInLuaのOO実装を使って、飛べるというプロパティを持ち、他の鳥オブジェクトのベースとなるBirdオブジェクトと、鳥の一種であるが飛べないOstrichオブジェクトを作成しました。 結果は明らかです:BirdとOstrichは別々の状態を持っています。

local Bird = {CanFly = true} 
  function Bird:New() 
  local b = {} 
    setmetatable(b, self) 
    selfself.__index = self 
  return b 
    終了 
  local   ダチョウ = Bird:New() --Bird.CanFly is true, Ostrich.CanFly is true 
  Ostrich.CanFly = false --Bird.CanFly is true, Ostrich.CanFly is false 

__indexとは対照的に、__newindexはテーブルのキーが更新された時に発生します。 これらのイベントは、テーブルのキーにrawsetとrawgetを使用することでスキップすることができます。

通話と傍受

JavaやC#では動的プロキシやAOPを実装するのに大変な手間がかかりますが、Luaではこのようなことはとても簡単で、限定的ではありますが、Luaの柔軟性を感じることができます。 これが__call操作で、値が呼び出された時に発動します。

              a = {}   
function a:Func()   
print("simonw")   
  終了   
c = {}   
c.__call = function(t, )   
print("Start")   
t.Func()   
print("End")   end   
setmetatable(a, c)   
a()   
--[[   
Start   
simonw   
End   ]] 
Read next

Firefoxのプラグインブロッカーはベータ版から脱却し、Flashはブロックされる

マルウェア、逃げられない最新のベータ版のリリースにより、Mozilla Foundation はすべての Firefox プラグインでポイント&クリック機能を利用できるようにするため、新たな一歩を踏み出しました。

Jul 14, 2025 · 2 min read