哪些Ruby类支持.clone?

Ruby在Object中定义了#clone 。 令我惊讶的是,有些课程在调用时会引发exception。 我发现NilClassTrueClassFalseClassFixnum都有这种行为。

1)是否存在完整的类列表(至少是核心类),不允许#clone ? 或者有没有办法检测特定类是否支持#clone

2) 42.clone什么问题?

我认为没有正式的清单,至少除非你算上读源。 原因2)不起作用是因为应用于Fixnums的优化。 它们作为实际值在内部存储/传递(所以是true,false和nil),而不是指针。 天真的解决方案就是让42.clone返回相同的42 ,但是不变的obj.clone.object_id != obj.object_id将不再保留, 42.clone实际上不会克隆。

Fixnum是一个特殊的类,由语言给予特殊处理。 从程序启动的时间开始,对于类可以表示的每个数字,只有一个Fixnum,并且它们被赋予一个不占用任何额外空间的特殊表示 – 这样,基本的数学运算就不会分配和解除分配记忆犹如疯狂。 因此,不能超过42个。

对于其他人来说,他们都有一个共同点:他们是单身人士。 根据定义,只有一个单例类的实例,因此尝试克隆它是一个错误。

我仍然不知道如何正确地测试克隆性,但这是使用错误捕获测试clonablity的一种非常笨重,邪恶的方法:

 def clonable?(value) begin clone = value.clone true rescue false end end 

这就是你如何克隆甚至不可克隆的东西。 至少对于很少的课程,我已经厌倦了。

 def super_mega_clone(value) eval(value.inspect) end 

以下是一些示例测试:

 b = :b puts "clonable? #{clonable? b}" b = proc { b == "b" } puts "clonable? #{clonable? b}" b = [:a, :b, :c] c = super_mega_clone(b) puts "c: #{c.object_id}" puts "b: #{b.object_id}" puts "b == c => #{b == c}" b.each_with_index do |value, index| puts "[#{index}] b: #{b[index].object_id} c: #{c[index].object_id}" end b[0] = :z puts "b == c => #{b == c}" b.each_with_index do |value, index| puts "[#{index}] b: #{b[index].object_id} c: #{c[index].object_id}" end b = :a c = super_mega_clone(b) puts "b: #{b.object_id} c: #{c.object_id}" > clonable? false > clonable? true > c: 2153757040 > b: 2153757480 > b == c => true > [0] b: 255528 c: 255528 > [1] b: 255688 c: 255688 > [2] b: 374568 c: 374568 > b == c => false > [0] b: 1023528 c: 255528 > [1] b: 255688 c: 255688 > [2] b: 374568 c: 374568 > b: 255528 c: 255528 

我做了一个git grep "can't clone" YARV的源代码,并得到了

 lib/singleton.rb: raise TypeError, "can't clone instance of singleton #{self.class}" object.c: rb_raise(rb_eTypeError, "can't clone %s", rb_obj_classname(obj)); test/test_singleton.rb: expected = "can't clone instance of singleton TestSingleton::SingletonTest" 

第一行和第三行表示您无法克隆单例。

第二行是指rb_special_const_p(obj) 。 但这超出了我的范围。

您无法克隆不可变类。 即你只能有一个对象42的实例(作为Fixnum),但可以有许多“42”的实例(因为字符串是可变的)。 你也不能克隆符号,因为它们就像不可变的字符串。

您可以使用object_id方法在IRB中检查它。 (符号和fixnums在重复调用后会给你相同的object_id)

Rails似乎用“可复制的?()”方法扩展了你提到的类。

http://api.rubyonrails.org/files/activesupport/lib/active_support/core_ext/object/duplicable_rb.html