2013-01-24 18 views
5

Próbuję serializacji i deserializacji zamknięcia LuaLua i serializowane zamknięcia

moje podstawowe zrozumienie jest, że poniżej fabryka powinna generować zamknięć (i to znacznie Lua nie rozróżnia funkcji i zamknięć - czyli tam ma typu „zamknięcie”)

> 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! 

, że oczekuje się, że całkowita 5 być serializowane z f1. Lub, jeśli string.dump nie może obsłużyć zamknięć, oczekiwałem błędu.

Dostaję się zupełnie inaczej (ale więcej, niż się spodziewałem) w wyniku łagodnej zmiany. Wygląda na to, że f2 jest rzeczywiście zamknięciem, ale string.dump nie próbował serializować wartości x w czasie, gdy był serializowany.

The docs nie pomagają mi. (co mają na myśli "... z nowymi upustami"?)

> 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 ? 

Odpowiedz

1

Dokumenty są dość jasne. string.dump nie obsługuje zamknięć używających upvalues. dzieje się tak dlatego, że wartością up to może być cokolwiek (włączając w to dane użytkownika, i jak Lua wiedziałaby, jak to przekształcić?)

upvue są zmiennymi zewnętrznymi, które są lokalne dla funkcji ze względu na zakres/zamknięcie. ponieważ x w twoim przykładzie jest upvue do funkcji zwróconej przez ffactory, to nie jest serializowane.

jeśli chcesz wesprzeć ten jakoś trzeba by przechowywać upvalues ​​siebie i ustawić je ponownie po tym, jak rozszeregować funkcji, takich jak to:

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

Dziękuję. Nie wiedziałem o debug.setupvalue. Czy możesz pokazać mi, gdzie w dokumentach jest wyjaśniona obsługa upvalues ​​string.dump (nie tutaj: http://www.lua.org/manual/5.2/manual.html#pdf-string.dump). Czy zwrot z _ENV jest oczekiwanym zachowaniem w moim pierwszym przykładzie? – Paul

+0

możesz przeczytać o debug.getupvalue [tutaj] (http://www.lua.org/manual/5.2/manual.html#pdf-debug.setupvalue). Nie jestem pewien, co to jest umowa w pierwszym przykładzie, ponieważ nie powinien nawet kompilacji. używasz load(), ale faktycznie powinno używać loadstring(). load pobiera func i string. –

+0

Już nie. Lua 5.2 ma przestarzałe 'loadstring' i używa tylko' load' dla obu łańcuchów i funkcji: http://www.lua.org/manual/5.2/manual.html#8.2 'loadstring' jest jednak nadal dostępny i daje ten sam wynik co 'load'. Dzięki jeszcze raz! – Paul

6

można zrobić coś takiego, aby zapisać/przywrócić te upvalues ​​(uwaga to nie obsługiwać upvalues ​​współdzielone pomiędzy różnymi funkcjami):

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

ta działa zarówno Lua Lua 5,1 i 5,2.

Uwaga ciekawy wynik, jeśli zmienisz ffactory nieznacznie (dodane math.abs(0); wszystko, co wykorzystuje globalną tabelę w żaden sposób zrobi):

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

Teraz, jeśli przywrócić upvalues ​​Ci uzyskać taki sam efekt, ale jeśli nie przywracaj wartości upuszczanych, w wyniku których wystąpił błąd w czasie działania w 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 ?