metatableと文字列連結

尊敬する @shunuhsせんせーが梅.py hackathonにて「華麗なるlua講座」を執り行うとの事。残念ながら僕は用事にて出席できなく、非常に残念なのと申し訳ないのとで、せめても、となんかエントリ書いてみる。
luaの特徴というとやはり、C/C++に簡単に組み込める事と、そのI/Fがスタックベースというバイナリアンには非常に分かりやすい考え方なのと、低フットプリントであること、そのくせmetatableの概念により簡単にクラスもどきが作れて、しかも演算子のオーバーライドも可能、というウマいヤスいハヤい(?)だったりする。しかし気に入らない部分もいくつか

  1. 配列(実はその実態はtable、このあたりもJSっぽい)が1はじまり
  2. 文字列連結が .. ってなに、分かりにくい

てなところ(ワガママ・・・)。この2番目をなんとかしてみようとか。

metatable

luaではtableに metatableを指定して、各種挙動をコントロールする事ができる。例えば __tostring(文字列に変換するメソッド), __index(キーが無い場合に呼ばれるメソッド・・・要するにこれをインスタンスメソッドに使う)とか__add, __subとかの演算系メソッドなどがある。設定は単純にこれらの名前で作ったtableを

t = {}
setmetatable(t, { __tostring = function() .... end } )

のようにひも付けしてやればオK。上の例だと文字列にしようとすると上記のラムダが呼び出される。

文字列連結

というわけでこれを使って _addをひも付けしてやれば + で連結できるという仕組み。

> a = {val="tugi"}
> b = {val="hagi"}
> S = {__add = function(s1, s2) return s1.val .. s2.val end}
> setmetatable(a, S)
> setmetatable(b, S)
> print(a+b)
tugihagi

結局クラスにしてしまうのが正解かな。

String = {}
function String:new(str)
        t = {}
        t.string = str
        String.__index = String
        String.__add = function (left, right) return String:new(left.string .. right.string) end
        String.__tostring = function (str) return str.string end
        setmetatable(t, String)
        return t
end

a = String:new("tugi")
b = String:new("hagi")
print (a);
print (b);
print (a+b);

でけた。

sardine% lua String.lua 
tugi
hagi
tugihagi

おkっぽい。