我使用Marshal.dump将SortedSet对象保存在文件中。 集合中的元素也是对象(包括Comparable并实现< =>方法)。
稍后在使用Marshal.load恢复该对象时,从文件加载的SortedSet未排序...
知道为什么或如何解决它?
以下是重现问题的简化示例:
require 'set'
class Foo
include Comparable
attr_accessor :num
def initialize(num)
@num = num
end
def <=>(other)
num <=> other.num
end
end
f1 = Foo.new(1)
f2 = Foo.new(2)
f3 = Foo.new(3)
s = SortedSet.new([f2, f1, f3])
File.open('set_test.dump', 'wb') { |f| Marshal.dump(s, f) }
比,从我使用的文件中加载对象 -
File.open('set_test.dump', 'rb') { |f| ls = Marshal.load(f) }
**我使用Rails 3.2.3和Ruby 2.1.8
**从文件加载转储时 - 在新的/单独的rails控制台中执行(并且不要忘记复制粘贴Foo类的定义:-))
答案 0 :(得分:4)
我可以在我试过的每一个Ruby上重现这种行为。
# write_sorted_set.rb
require 'set'
class Foo
include Comparable
attr_accessor :num
def initialize(num)
@num = num
end
def <=>(other)
num <=> other.num
end
end
f1 = Foo.new(1)
f2 = Foo.new(2)
f3 = Foo.new(3)
s = SortedSet.new([f2, f1, f3])
File.open('set_test.dump', 'wb') { |f| Marshal.dump(s, f) }
p s.to_a
和
# load_sorted_set.rb
require 'set'
class Foo
include Comparable
attr_accessor :num
def initialize(num)
@num = num
end
def <=>(other)
num <=> other.num
end
end
ls = Marshal.load(File.binread('set_test.dump'))
p ls.to_a
启动时
ruby write_sorted_set.rb && ruby load_sorted_set.rb
输出
[#<Foo:0x000000010cae30 @num=1>, #<Foo:0x000000010cae08 @num=2>, #<Foo:0x000000010cadb8 @num=3>]
[#<Foo:0x0000000089be08 @num=2>, #<Foo:0x0000000089bd18 @num=1>, #<Foo:0x0000000089bc78 @num=3>]
使用此定义:
class Foo
attr_accessor :num
def initialize(num)
@num = num
end
end
load_sorted_set.rb
中的应引发异常(comparison of Foo with Foo failed (ArgumentError)
),但事实并非如此。看起来SortedSet
Marshal.load
查看SortedSet
的{{3}}:
module_eval {
# a hack to shut up warning
alias old_init initialize
}
和
module_eval {
# a hack to shut up warning
remove_method :old_init
}
@@setup = true
end
end
def initialize(*args, &block) # :nodoc:
SortedSet.setup
initialize(*args, &block)
end
end
看起来SortedSet
已修补,以确保在SortedSet.setup
初始化之前执行SortedSet
。
Marshal.load
似乎并不知道这一点。
你可以打电话
SortedSet.setup
在require 'set'
之后和Marshal.load
之前
您可以强制SortedSet
初始化:
ls = SortedSet.new(Marshal.load(File.binread('set_test.dump')))