2013-01-24 9 views
5

Ich versuche, eine Lua Schließung zu serialisiert und deserialisiertLua und serialisiert Schließungen

mein Grundverständnis ist, dass die unter Fabrikschließungen erzeugen sollte (und das Lua unterscheidet nicht viel zwischen den Funktionen und Schließungen - dh es ist kein Typ 'Schließung')

> 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 die ganze Zahl 5 mit f1 serialisiert werden erwartet. Oder, wenn string.dump Schließungen nicht verarbeiten kann, erwartete ich einen Fehler.

Ich bekomme ganz anders (aber mehr, was ich erwartet habe) Ergebnisse mit einer leichten Veränderung. Es sieht aus wie f2 ist in der Tat eine Schließung, aber string.dump hat nicht versucht, den Wert von x zum Zeitpunkt der Serialisierung zu serialisieren.

Die docs helfen mir nicht viel. (Was bedeuten sie mit "... mit neuen 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 ? 

Antwort

1

die Dokumente sind ziemlich klar. string.dump verarbeitet keine Closures mit Upvalues. Das liegt daran, dass die Upvalues ​​alles sein könnten (einschließlich Userdata und wie würde Lua wissen, wie das zu serialisieren ist?)

upvalues ​​sind die externen Variablen, die aufgrund von Scoping/Closures lokal für eine Funktion sind. Da x in Ihrem Beispiel ein Upvalue für die von ffactory zurückgegebene Funktion ist, wird es nicht serialisiert.

wenn man irgendwie diese unterstützen möchten, würden Sie sich selbst von den upvalues ​​speichern haben und sie wieder ein, nachdem Sie die Funktion deserialisiert haben, wie folgt aus:

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

Vielen Dank. Ich wusste nicht über debug.setupvalue. Können Sie mir zeigen, wo in den Dokumenten die Handhabung der upvalues ​​von string.dump erklärt wird (nicht hier: http://www.lua.org/manual/5.2/manual.html#pdf-string.dump). Ist die Rückkehr von _ENV das erwartete Verhalten in meinem ersten Beispiel? – Paul

+0

können Sie lesen über debug.getupvalue [hier] (http://www.lua.org/manual/5.2/manual.html#pdf-debug.setupvalue). Ich bin mir nicht sicher, was der Deal in Ihrem ersten Beispiel ist, da es nicht einmal kompilieren sollte. Sie verwenden load(), sollten aber eigentlich loadstring() verwenden. load benötigt eine Funktion und eine Zeichenfolge. –

+0

Nicht mehr. Lua 5.2 hat 'loastring' veraltet und verwendet nur' load' für Strings und Funktionen: http://www.lua.org/manual/5.2/manual.html#8.2 'loadstring' ist jedoch immer noch verfügbar und gibt die Das gleiche Ergebnis wie 'load'. Danke noch einmal! – Paul

6

Sie können so etwas tun, um zu sparen/restore diese upvalues ​​(es zu beachten ist upvalues ​​nicht umgehen zwischen verschiedenen Funktionen gemeinsam):

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

Diese 5.2 sowohl unter Lua 5.1 und Lua funktioniert.

Hinweis ein interessantes Ergebnis, wenn Sie ffactory leicht ändern (hinzugefügt math.abs(0), alles, was in irgendeiner Weise globale Tabelle verwendet tun wird): Jetzt

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

wenn Sie upvalues ​​Sie das gleiche Ergebnis wiederherstellen, aber wenn Sie upvalues ​​nicht wiederherstellen, erhalten Sie einen Laufzeitfehler unter Lua 5.2: