2013-01-24 39 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! 

我預期整數5與f1被序列化。或者,如果string.dump無法處理關閉,我預計會發生錯誤。

我得到了完全不同的結果(但我期望的結果)有輕微的變化。它看起來像f2確實是一個閉包,但string.dump並沒有試圖在序列化時序列化x的值。

docs對我幫助不大。 (它們是什麼意思「... with new upvalues」?)

> 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的閉包。這是因爲upvalues可能是任何東西(包括用戶數據,以及Lua如何序列化它)?

upvalues是由於作用域/關閉而對函數局部的外部變量。因爲在你的例子中x是ffactory返回的函數的一個升序,所以它不會被序列化。

,如果你想以某種方式支持這一點,你就必須自己保存upvalues和重新設置你的反序列化功能之後,就像這樣:

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()。加載需要一個func和一個字符串。 –

+0

不再。 Lua 5.2已經棄用'loadstring'並且只對字符串和函數使用'load':然而,http://www.lua.org/manual/5.2/manual.html#8.2'loadstring'仍然可用,並且給出了與'load'相同的結果。再次感謝! – Paul

6

你可以做這樣的事情,以節省/恢復那些upvalues(注意它不處理不同的功能之間共享upvalues):

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()) 

這適用的Lua 5.1和Lua 5.2下。

注意一個有趣的結果,如果你改變ffactory略(添加math.abs(0);任何使用全局表以任何方式都行):如果你恢復你得到同樣的結果upvalues

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

現在,但如果你不恢復upvalues你得到一個運行時錯誤Lua 5.2下:

lua.exe: upvalues.lua:19: attempt to index upvalue '_ENV' (a nil value) 
stack traceback: 
upvalues.lua:19: in function 'f2' 
upvalues.lua:24: in main chunk 
[C]: in ?