deserializing một đối tượng từ YAML không sử dụng phương pháp initialize
bởi vì nói chung không có sự tương ứng giữa các biến đối tượng của đối tượng (đó là những gì các cửa hàng tuần tự hóa Yaml mặc định) và các tham số cho initialize
.
Như một ví dụ, hãy xem xét một đối tượng với một initialize
trông như thế này (không có biến dụ khác):
def initialize(param_one, param_two)
@a_variable = some_calculation(param_one, param_two)
end
Bây giờ khi một thể hiện của điều này được deserialized, bộ vi xử lý YAML có giá trị cho @a_variable
, nhưng phương pháp initialize
yêu cầu hai thông số, do đó, nó không thể gọi nó. Ngay cả khi số lượng biến mẫu khớp với số lượng tham số đến initialize
thì không nhất thiết phải là trường hợp chúng tương ứng và ngay cả khi chúng đã xử lý không biết thứ tự chúng được chuyển đến initialize
. Quy trình mặc định để tuần tự hóa và deserializing một đối tượng Ruby thành Yaml là viết ra tất cả các biến cá thể (với tên của chúng) trong quá trình tuần tự, sau đó khi deserializing cấp phát một thể hiện mới của lớp và chỉ cần đặt cùng một biến mẫu trên ví dụ mới.
Tất nhiên đôi khi bạn cần kiểm soát nhiều hơn quá trình này. Nếu bạn đang sử dụng bộ xử lý Psych Yaml (đó là mặc định trong Ruby 1.9.3) thì bạn nên thực hiện các phương thức encode_with
(cho tuần tự hóa) hoặc hoặc init_with
(để giải tuần tự) khi thích hợp.
Để tuần tự hóa, Psych sẽ gọi phương thức encode_with
của đối tượng nếu có, đi qua coder
object. Đối tượng này cho phép bạn chỉ định cách đối tượng sẽ được biểu diễn trong Yaml - thông thường bạn chỉ xem nó như một băm.
Để hủy tuần tự hóa, Psych sẽ gọi phương thức init_with
nếu phương thức này xuất hiện trên đối tượng của bạn thay vì sử dụng quy trình mặc định được mô tả ở trên, một lần nữa chuyển đối tượng coder
. Lần này, coder
sẽ chứa thông tin về các đối tượng đối tượng trong Yaml.
Lưu ý rằng bạn không cần phải cung cấp cả hai phương pháp, bạn chỉ có thể cung cấp cả hai phương pháp nếu bạn muốn. Nếu bạn cung cấp cả hai, đối tượng coder
mà bạn nhận được qua số init_with
về cơ bản sẽ giống như đối tượng được chuyển đến encode_with
sau khi phương thức đó đã chạy. Ví dụ, hãy xem xét một đối tượng có một số biến mẫu được tính toán từ những người khác (có lẽ là tối ưu hóa để tránh tính toán lớn), nhưng không nên được tuần tự hóa thành 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
Khi bạn đổ một thể hiện của lớp này để YAML, nó sẽ giống như thế này, mà không có giá trị calculated
:
--- !ruby/object:Foo
first: 1
second: 2
Khi bạn tải YAML này trở lại vào Ruby, các đối tượng được tạo ra sẽ có bộ biến mẫu @calculated
.
Nếu bạn muốn bạn thể gọi initialize
từ bên trong init_with
, nhưng tôi nghĩ rằng nó sẽ được tốt hơn để giữ một sự tách biệt rõ ràng giữa khởi tạo một mới thể hiện của lớp, và deserializing một dụ hiện từ YAML . Tôi khuyên bạn nên trích xuất logic chung thành các phương thức có thể được gọi từ cả hai thay vào đó,
Có thể trùng lặp: http: // stackoverflow.com/questions/1823386/calling-initialize-when-loading-an-object-serialized-with-yaml –
Bài đăng đó hữu ích, tuy nhiên nó không hoàn toàn giải quyết được vấn đề của tôi. Dòng YAML mà tôi phân tích từ phức tạp hơn một đối tượng duy nhất, đó là nhiều đối tượng, một số trong đó bao gồm các đối tượng khác. – clementine
Rất tiếc, chỉ cần thử. Có lẽ điều này hữu ích hơn: Để tìm hiểu _why_ 'YAML :: load' không _not_ gọi' initialize', hãy kiểm tra nguồn. : P Hoặc có lẽ chúng ta có thể chờ một người trả lời biết nhiều hơn về các chi tiết. Tôi đã thử 'đặt d.class == c.class' trong kịch bản của bạn và thấy nó đúng. Vì vậy, +1 về câu hỏi của bạn. –