スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

Plutoを使ってLuaの状態を永続化(メタテーブル編)

メタテーブルは、何もしなければ勝手に保存されて復元されるようだ。
この挙動を変えたい時はメタテーブルの__persistフィールドを設定する。
  • trueを指定した場合
    普通に永続化されるらしい。userdataはたぶんバイト列として書き出されるんだろう。だが、復元した時にメタテーブルが新たに作られることになるので、環境の一部分だけ保存する時は注意が必要な気がする。
  • falseを指定した場合
    永続化しようとするとエラーになるらしい。
  • 関数を指定した場合
    その関数は引数に、永続化するオブジェクトを受け取る。で、そのオブジェクトを作り直す関数を返す。
  • 指定しなかった場合
    もう書いた。userdataだとエラーになるらしい。
実際に試してみよう。
適当にこんなモジュールをでっちあげた。

-- vector.lua
local tostring = tostring
local setmetatable = setmetatable
module "vector"
local vector_meta = {}
function vector_meta.__add(a,b)
  return new(a.x+b.x,a.y+b.y)
end
function vector_meta.__sub(a,b)
  return new(a.x-b.x,a.y-b.y)
end
function vector_meta.__unm(a)
  return new(-a.x,-a.y)
end
function vector_meta.__eq(a,b)
  return a.x == b.x and a.y == b.y
end
function vector_meta.__tostring(a)
  return "("..tostring(a.x)..","..tostring(a.y)..")"
end
function new(x,y)
  return setmetatable({x=x,y=y},vector_meta)
end
で、書き出す側。メタテーブルに__persistが指定されていないのでメタテーブルごと永続化される。メタメソッドでsetmetatableとtostringを上位値として使ってるのでpermsに入れておく。

require "vector"
require "pluto"

local myobj = {}
myobj.a = vector.new(1,2)
myobj.b = vector.new(-4,7)
myobj.c = myobj.a+myobj.b
myobj.d = myobj.a-myobj.b

local perms = {}
perms[setmetatable] = "setmetatable"
perms[tostring] = "tostring"

local f = io.open("hogehoge","wb")
f:write(pluto.persist(perms,myobj))
f:close()
読み込み側。

require "pluto"
require "vector"

local f = io.open("hogehoge","rb")
local data = f:read("*a")
f:close()

local perms = {}
perms["setmetatable"] = setmetatable
perms["tostring"] = tostring

local myobj = pluto.unpersist(perms,data)
print(myobj.a)
print(myobj.b)
print(myobj.a+myobj.b,myobj.c)
print(myobj.a-myobj.b,myobj.d)
local a = vector.new(1,2)
print(a == myobj.a) -- どっちも(1,2)なのに…
最後の結果に注目。メタテーブルが異なるので、__eqを設定しても呼ばれない。
ただ、vectorモジュールも含めて環境を全て永続化する場合は問題無いと思われる。
次に、__persist関数を実装してみる。

-- vector.luaに書き足す
function vector_meta.__persist(a)
  local x = a.x
  local y = a.y
  return function()
    -- オブジェクトを作り直す
    return new(x,y)
  end
end
「作り直し関数」の中でvector.newを呼び出しているので、permsに入れておく。

require "vector"
require "pluto"

local myobj = {}
myobj.a = vector.new(1,2)
myobj.b = vector.new(-4,7)
myobj.c = myobj.a+myobj.b
myobj.d = myobj.a-myobj.b
print(myobj.a)

local perms = {}
perms[vector.new] = "vector.new"

local f = io.open("hogehoge","wb")
f:write(pluto.persist(perms,myobj))
f:close()

require "pluto"
require "vector"

local f = io.open("hogehoge","rb")
local data = f:read("*a")
f:close()

local perms = {}
perms["vector.new"] = vector.new

local myobj = pluto.unpersist(perms,data)
print(myobj.a)
print(myobj.b)
print(myobj.a+myobj.b,myobj.c)
print(myobj.a-myobj.b,myobj.d)
local a = vector.new(1,2)
print(a == myobj.a)
スポンサーサイト

テーマ : プログラミング | ジャンル : コンピュータ

コメントの投稿

非公開コメント

プロフィール

minoki

Author:minoki
好きなプログラミング言語:
Haskell,Lua
GitHubアカウント
Twitter

最新記事
月別アーカイブ
カテゴリ
検索フォーム
上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。