Ruby Marshal.load 不保持排序集的顺序
Ruby Marshal.load doesn't keep order of sorted set
我正在使用 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
** 从文件加载转储时 - 在 new/seperate rails 控制台中执行(不要忘记复制粘贴 Foo class 的定义:-))
重现错误
我可以在每一次 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
in load_sorted_set.rb
应该引发异常 (comparison of Foo with Foo failed (ArgumentError)
),但它没有。看起来 SortedSet
没有被 Marshal.load
正确初始化
lib/set.rb
正在查看 SortedSet
的 sourcecode :
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
你可以打电话
SortedSet.setup
在require 'set'
之后和Marshal.load
之前
SortedSet.new
您可以使用 :
强制执行 SortedSet
初始化
ls = SortedSet.new(Marshal.load(File.binread('set_test.dump')))
我正在使用 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
** 从文件加载转储时 - 在 new/seperate rails 控制台中执行(不要忘记复制粘贴 Foo class 的定义:-))
重现错误
我可以在每一次 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
in load_sorted_set.rb
应该引发异常 (comparison of Foo with Foo failed (ArgumentError)
),但它没有。看起来 SortedSet
没有被 Marshal.load
lib/set.rb
正在查看 SortedSet
的 sourcecode :
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
你可以打电话
SortedSet.setup
在require 'set'
之后和Marshal.load
之前
SortedSet.new
您可以使用 :
强制执行SortedSet
初始化
ls = SortedSet.new(Marshal.load(File.binread('set_test.dump')))