アーカイブ

‘Lua’ カテゴリーのアーカイブ

Luaのdestructor(デストラクタ)とGC

2009 年 6 月 2 日
コメントは受け付けていません。

LuaにはGCが付いていますので、使われなくなったメモリは回収されます。

強制的に呼び出すのは簡単で、回収したいところで

collectgarbage(“collect”)

とするだけです。

C++ではクラスインスタンスの解放時にデストラクタが呼ばれます。

自前のリソースの解放には便利です。

さっそく、Luaの自作クラスでやってみます。

何やらメタテーブルに__gcメソッドを書けばよろしいようで、簡単簡単。

function destruct()
        print("destructor called")
end

t = {}
setmetatable(t, {__gc = destruct})

t = nil
collectgarbage("collect")
print("end")

実行してみたものの、endしか表示されず、destruct関数が呼ばれない・・・

仕様を見てみると、ユーザデータ(テーブルではない)のメタテーブルに対して

__gcメソッドを定義しないといけない模様・・・

ユーザデータを作ってくれるnewproxy関数を発見!

この関数は非公開メソッドのようです。

この関数の引数がtrueなら、新しいメタテーブルを内包するユーザデータを作ります。

引数が既に作成してあるユーザデータなら、そのユーザデータに含まれるメタテーブルをコピーします。

先ほどのプログラムを次のように変更します。

function destruct()
        print("destructor called")
end

t = {_udata = newproxy(true) }
setmetatable(t._udata, {__gc = destruct})
t = nil
collectgarbage("collect")
print("end")

うまくいくだろうと思いきや、Luaが怒りました。

bad argument #1 to ‘setmetatable’ (table expected, got userdata)

つまり、setmetatable関数にはテーブルしか指定できないようです。

また調べると、getmetatable関数はユーザデータでも構わないとののこと。

もう一度プログラムを書き換えてみました。

function destruct()
        print("destructor called")
end

t = {_udata = newproxy(true) }
getmetatable(t._udata).__gc = destruct
t = nil
collectgarbage("collect")
print("end")

実行してみると・・・無事デストラクタが呼び出されました。

destructor called
end

admin Lua

Luaでcall_user_func 〜 クラスメソッドを変数で呼び出したい

2009 年 6 月 2 日
コメントは受け付けていません。

PHPのcall_user_func関数って便利です。

イベント駆動系のプログラムを書くときには必須です。

そんな関数がLuaにはない・・・ (見つけられないだけかも知れませんが)

ということで、試作してみました。

function call_user_func(func, ...)
        local t = type(func)
        if t == 'function' then
                return func(...)
        elseif t == 'string' then
                if _G[func] == nil or type(_G[func]) ~= 'function' then
                        error("function is not defined '"..func.."'")
                end
                return _G[func](...)
        elseif t == 'table' then
                local _instance = func[1]
                local _method = func[2]
                if _instance == nil or _method == nil then
                        error("instance or method name is nil")
                end
                if _instance[_method] == nil then
                        error("class method is not defined '".._method.."'")
                end
                return _instance[_method](_instance, ...)
        else
                error("func is not matched type '"..type(func).."'")
        end
end

function funcA(name)
        print("My name is "..name)
end

Class = {}

function Class:new(name)
        local t = {name = name}
        setmetatable(t, {__index = Class})
        return t
end

function Class:funcA()
        print("I am "..self.name)
end

function Class:funcB(...)
        self:funcA()
        print("data are "..table.concat({...}, ","))
end

a = Class:new("taro")
a:funcA()
a:funcB("1", "2", "3")

call_user_func({a, "funcB"}, "a", "b", "c")
call_user_func(funcA, "jiro")
call_user_func("funcA", "saburo")

実行結果は正常

I am taro
I am taro
data are 1,2,3
I am taro
data are a,b,c
My name is jiro
My name is saburo

19行目の_instance[_method](_instance, …)が肝です。

メソッドの第1引数はインスタンスを格納しなければならないオキテがあります。

よって、直接引数を…にしてしまうと、おかしなことになりますから注意!

admin Lua ,