2013-01-24 14 views
5

私はLuaのクロージャをシリアライズおよびデシリアライズするLuaのシリアライズ閉鎖

をしようとしている私の基本的な理解は、以下の工場が閉鎖を生成する必要があること(およびLuaは多くの関数とクロージャとを区別しないということである - つまり、そこに何種類 '閉鎖')

> function ffactory(x) return function() return x end end 
> f1 = ffactory(5) 
> print(f1()) 
5      <-- so far so good 
> s = string.dump(f1) 
> f2 = load(s) 
> print(f2()) 
table: 00000000002F7BA0 <-- expected the integer 5 
> print(f2()==_ENV) 
true      <-- definitely didn't expect this! 

は、iは整数5は、f1とシリアル化されることが期待されていません。または、string.dumpがクロージャを処理できない場合は、エラーが予想されます。

私は、(私が予想したより多くの)結果は軽度の変化を伴います。 f2は実際にクロージャですが、string.dumpはシリアル化された時点でxの値をシリアル化しようとしませんでした。

docsは私をあまり助けません。 (「新しい上位値ではどういう意味ですか?」)

> function ffactory(x) return function() return x+1 end end 
> f1 = ffactory(5) 
> print(f1()) 
6      <-- good 
> s = string.dump(f1) 
> f2 = load(s) 
> print(f2()) 
stdin:1: attempt to perform arithmetic on upvalue 'x' (a table value) 
stack traceback: 
     stdin:1: in function 'f2' 
     stdin:1: in main chunk 
     [C]: in ? 

答えて

1

ドキュメントはかなり明確です。 string.dumpはupvaluesを使ってクロージャを処理しません。これは、上位値が何か(ユーザデータを含む)であり、Luaがそれをどのようにシリアル化するかを知っているからでしょうか?

upvaluesはスコープ/クロージャによる関数のローカルな外部変数です。あなたの例のxはffactoryが返す関数の上位値なので、シリアル化されません。

あなたが何らかの形でこれをサポートしたい場合はこのように、機能を非直列化した後、あなたは上位値を自分で保存し、それらを再度設定する必要があります:

function ffactory(x) 
    return function() return x+1 end 
end 

local f1 = ffactory(5) 
print(f1()) 

local s = string.dump(f1) 
f2 = loadstring(s) 
debug.setupvalue(f2, 1, 5) 
print(f2()) 
+1

ありがとうございます。私はdebug.setupvalueを知らなかった。ドキュメントで、string.dumpのupvalues(ここではなく、http://www.lua.org/manual/5.2/manual.html#pdf-string.dump)の取り扱いについて説明しています。また、私の最初の例で期待される動作を_ENVに戻していますか? – Paul

+0

あなたはdebug.getupvalue [here](http://www.lua.org/manual/5.2/manual.html#pdf-debug.setupvalue)について読むことができます。私はそれがコンパイルされるべきではないので、あなたの最初の例に何があるか分かりません。 load()を使用していますが、実際にはloadstring()を使用する必要があります。 loadはfuncと文字列をとります。 –

+0

もうしません。 Lua 5.2は 'loadstring'を廃止し、文字列と関数の両方に' load'だけを使用しています:http://www.lua.org/manual/5.2/manual.html#8.2 'loadstring'はまだ利用可能ですが、 'load'と同じ結果になります。再度、感謝します! – Paul

6

あなたが保存するには、このような何かを行うことができます/(異なる関数間で共有される上位値を処理しないことに注意してください)、それらの上位値を復元する:これは、両方のLua 5.1とLuaの5.2で動作

local function capture(func) 
    local vars = {} 
    local i = 1 
    while true do 
    local name, value = debug.getupvalue(func, i) 
    if not name then break end 
    vars[i] = value 
    i = i + 1 
    end 
    return vars 
end 

local function restore(func, vars) 
    for i, value in ipairs(vars) do 
    debug.setupvalue(func, i, value) 
    end 
end 

function ffactory(x) return function() return x end end 
local f1 = ffactory(5) 
local f2 = (loadstring or load)(string.dump(f1)) 
restore(f2, capture(f1)) --<-- this restored upvalues from f1 for f2 

print(f1(), f2()) 

を。あなたが上位値を復元する場合

function ffactory(x) return function() math.abs(0) return x end end 

は今、あなたは同じ結果を得るが、あなたの場合:;あなたはffactoryを変更した場合

注興味深い結果が、わずかに(どのような方法で、グローバルテーブルを使用して何が行いますmath.abs(0)を追加しました)あなたがルア5.2の下で実行時エラーを取得するupvaluesを復元しないでください: