哪些Ruby类支持.clone?
Ruby在Object中定义了#clone
。 令我惊讶的是,有些课程在调用时会引发exception。 我发现NilClass , TrueClass , FalseClass , Fixnum都有这种行为。
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