5

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 の値をシリアル化しようとしませんでした。

ドキュメントはあまり役に立ちません。("...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 ?
4

2 に答える 2

7

これらの上位値を保存/復元するには、次のようにすることができます (異なる関数間で共有される上位値を処理しないことに注意してください)。

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); グローバル テーブルを何らかの方法で使用するものはすべて実行されます)。

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

upvalues を復元すると同じ結果が得られますが、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 ?
于 2013-01-25T03:15:01.413 に答える
1

ドキュメントはかなり明確です。string.dump は、upv​​alues を使用してクロージャーを処理しません。これは、上位値が何でもかまいません (ユーザーデータを含み、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())
于 2013-01-24T20:35:07.430 に答える