Ruby 使用 JSON 序列化结构
Ruby serialize struct with JSON
我正在尝试将一个简单的结构序列化为 JSON,这工作正常,但我无法让它从 JSON 创建该结构的实例。这是我正在尝试的方法。
require 'rubygems'
require 'json'
Person = Struct.new(:name, :age)
json = Person.new('Adam', 19).to_json
puts json
me = JSON.load(json)
puts me.name
我得到以下输出:
"#<struct Person name=\"Adam\", age=19>"
/usr/lib/ruby/1.9.1/json/common.rb:148:in `parse': 746: unexpected token at '"#<struct Person name=\"Adam\", age=19>"' (JSON::ParserError)
from /usr/lib/ruby/1.9.1/json/common.rb:148:in `parse'
from /usr/lib/ruby/1.9.1/json/common.rb:309:in `load'
from why.rb:9:in `<main>'
在这种情况下,person.to_json
没有按照您的预期进行。
当您 require 'json'
时,JSON 库会在 Object
上插入一个 #to_json
方法,如果其他地方没有提供专门的 #to_json
方法,这是一个后备方法. This inserted method 与在对象上调用 #to_s#to_json
基本相同。
对于此处的 Person
class,#to_s
输出 standard Object#to_s
,默认情况下,它不提供可由 JSON图书馆。
但是,Struct
提供了一个 #to_h
方法,可用于将该结构转换为 Hash
,并且 Hash
是(在需要 JSON 库时)知道如何生成 JSON 可解析的输出。
所以简单地改变:
json = Person.new('Adam', 19).to_json
puts json
至:
person = Person.new('Adam', 19)
puts person.to_h.to_json
会如您所愿。
(顺便说一句,我实际上建议直接在 Person
class 上实现 #to_json
,因为调用 #to_h#to_json
违反了 Law of Demeter。)
您还可以使用 to_json
方法定义结构。取决于您是否满意致电 to_h.to_json
。如果只在一个class内部调用一次,可能还可以忍受,忽略这个。但是如果结构在整个系统中使用,下面是结构上的一个方便的辅助方法。
require 'struct'
require 'json'
MyStruct = Struct.new(:foo, :bar) do
def to_json
to_h.to_json
end
end
simple_struct = MyStruct.new("hello", "world")
simple_struct.to_json
# => "{\"foo\":\"hello\",\"bar\":\"world\"}"
我正在尝试将一个简单的结构序列化为 JSON,这工作正常,但我无法让它从 JSON 创建该结构的实例。这是我正在尝试的方法。
require 'rubygems'
require 'json'
Person = Struct.new(:name, :age)
json = Person.new('Adam', 19).to_json
puts json
me = JSON.load(json)
puts me.name
我得到以下输出:
"#<struct Person name=\"Adam\", age=19>"
/usr/lib/ruby/1.9.1/json/common.rb:148:in `parse': 746: unexpected token at '"#<struct Person name=\"Adam\", age=19>"' (JSON::ParserError)
from /usr/lib/ruby/1.9.1/json/common.rb:148:in `parse'
from /usr/lib/ruby/1.9.1/json/common.rb:309:in `load'
from why.rb:9:in `<main>'
在这种情况下,person.to_json
没有按照您的预期进行。
当您 require 'json'
时,JSON 库会在 Object
上插入一个 #to_json
方法,如果其他地方没有提供专门的 #to_json
方法,这是一个后备方法. This inserted method 与在对象上调用 #to_s#to_json
基本相同。
对于此处的 Person
class,#to_s
输出 standard Object#to_s
,默认情况下,它不提供可由 JSON图书馆。
但是,Struct
提供了一个 #to_h
方法,可用于将该结构转换为 Hash
,并且 Hash
是(在需要 JSON 库时)知道如何生成 JSON 可解析的输出。
所以简单地改变:
json = Person.new('Adam', 19).to_json
puts json
至:
person = Person.new('Adam', 19)
puts person.to_h.to_json
会如您所愿。
(顺便说一句,我实际上建议直接在 Person
class 上实现 #to_json
,因为调用 #to_h#to_json
违反了 Law of Demeter。)
您还可以使用 to_json
方法定义结构。取决于您是否满意致电 to_h.to_json
。如果只在一个class内部调用一次,可能还可以忍受,忽略这个。但是如果结构在整个系统中使用,下面是结构上的一个方便的辅助方法。
require 'struct'
require 'json'
MyStruct = Struct.new(:foo, :bar) do
def to_json
to_h.to_json
end
end
simple_struct = MyStruct.new("hello", "world")
simple_struct.to_json
# => "{\"foo\":\"hello\",\"bar\":\"world\"}"