反序列化從YAML對象不使用initialize
方法因爲一般情況下,對象實例變量(這是默認的Yaml序列化存儲的內容)與參數initialize
之間沒有對應關係。
作爲一個例子,考慮具有一個initialize
看起來像這樣的物體(沒有其他實例變量):
def initialize(param_one, param_two)
@a_variable = some_calculation(param_one, param_two)
end
現在,當這樣的一個實例被反序列化時,YAML處理器具有用於@a_variable
的值,但initialize
方法需要兩個參數,所以它不能調用它。即使實例變量的數量與initialize
的參數數量相匹配,它們並不一定就是它們對應的情況,即使它們確實處理器不知道它們應該傳遞給initialize
的順序。
將Ruby對象序列化和反序列化爲Yaml的默認過程是在序列化過程中寫出所有實例變量(及其名稱),然後在反序列化時分配一個新的類實例並簡單地在此上設置相同的實例變量新實例。
當然有時你需要更多的控制這個過程。如果您使用的是Psych Yaml處理器(這是Ruby 1.9.3中的默認處理器),那麼您應該適當地實現encode_with
(用於序列化)或或init_with
(用於反序列化)方法。
對於序列化,Psych會調用對象的encode_with
方法,如果它存在,則傳遞coder
object。這個對象允許你指定對象應該如何在Yaml中表示 - 通常你只是把它當作一個散列來對待。
對於反序列化,精極度緊張將調用init_with
方法,如果它是存在的對象,而不是使用上述的默認程序,再次通過一個coder
對象上。這次coder
將包含有關Yaml中對象表示的信息。
請注意,您不需要同時提供兩種方法,只需提供任意一種即可。如果您確實提供了這兩種方法,那麼您在init_with
中通過的coder
對象基本上與該方法運行後傳遞給encode_with
的對象相同。
作爲一個例子,考慮一個對象有一些實例變量是從別人計算出來的(也許作爲優化來避免大的計算),但不應該序列化到Yaml。
class Foo
def initialize(first, second)
@first = first
@second = second
@calculated = expensive_calculation(@first, @second)
end
def encode_with(coder)
# @calculated shouldn’t be serialized, so we just add the other two.
# We could provide different names to use in the Yaml here if we
# wanted (as long as the same names are used in init_with).
coder['first'] = @first
coder['second'] = @second
end
def init_with(coder)
# The Yaml only contains values for @first and @second, we need to
# recalculate @calculated so the object is valid.
@first = coder['first']
@second = coder['second']
@calculated = expensive_calculation(@first, @second)
end
# The expensive calculation
def expensive_calculation(a, b)
...
end
end
當你傾倒這個類YAML的一個實例,它會是這個樣子,沒有calculated
值:
--- !ruby/object:Foo
first: 1
second: 2
當加載這個YAML回紅寶石,所創建的對象將設置了@calculated
實例變量。
如果你想讓你能呼叫initialize
從init_with
內,但我認爲這將是更好地保持初始化類的新實例,從YAML反序列化現有實例之間的明確分工。我建議將通用邏輯提取爲可以從兩者調用的方法,而不是
可能的重複:http:// stackoverflow。com/questions/1823386/calling-initialize-when-loading-an-object-serialized-with-yaml –
該帖子很有幫助,但它並沒有完全解決我的問題。我解析的YAML流比單個對象更復雜,它是許多對象,其中一些由其他對象組成。 – clementine
對不起,只是想。也許這更有幫助:要找出_why_'YAML :: load'不會調用'initialize',請檢查源代碼。 :P或許我們可以等待一位瞭解更多細節的回答者。我確實在腳本中嘗試了'將d.class == c.class'並且發現它是真的。所以你的問題+1。 –