哪些 Ruby 类支持 .clone?

Posted

技术标签:

【中文标题】哪些 Ruby 类支持 .clone?【英文标题】:Which Ruby classes support .clone? 【发布时间】:2010-11-27 23:05:35 【问题描述】:

Ruby 在 Object 中定义了#clone。 令我惊讶的是,某些类在调用它时会引发异常。 我发现 NilClassTrueClassFalseClassFixnum 有这种行为。

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

2) 42.clone 有什么问题?

【问题讨论】:

我真的很想知道你如何测试一个类是否可以自己克隆。似乎如果一个类不想让自己被克隆,那么它应该将它从 Object 继承的克隆方法设为私有,这样你就可以只在 public_methods 下测试它的存在。对我来说似乎是常识 【参考方案1】:

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

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

【讨论】:

duplicatable?() 也在 ActiveSupport gem 中定义【参考方案2】:

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

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)。但这超出了我的理解范围。

【讨论】:

【参考方案3】:

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

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

【讨论】:

【参考方案4】:

Fixnum 是一个特殊的类,由语言给予特殊处理。从你的程序启动的那一刻起,类可以表示的每个数字都有一个 Fixnum,并且它们被赋予了一个不占用任何额外空间的特殊表示——这样,基本的数学运算就不会分配和释放记忆像疯了似的。因此,42 不能超过一个。

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

【讨论】:

“因此,42 不能超过一个。”。为什么需要?这是完美的。【参考方案5】:

我认为没有正式的列表,至少除非你算上阅读源代码。原因 2) 不起作用是因为对 Fixnums 进行了优化。它们作为实际值在内部存储/传递(true、false 和 nil 也是如此),而不是作为指针。幼稚的解决方案是让42.clone 返回相同的42,但不变的obj.clone.object_id != obj.object_id 将不再成立,42.clone 实际上不会被克隆。

【讨论】:

obj.clone.object_id != obj.object_id 为真和obj.clone.object_id == obj.object_id 并不总是为真是不同的。前者不成立,不代表后者不成立。【参考方案6】:

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

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

【讨论】:

Mutability 与它无关(实际上,您可以将状态添加到 Fixnum)。 Fixnum 的默认行为真的很奇怪,特别是考虑到它确实具有克隆方法 d.class.method_defined?(:clone) == true

以上是关于哪些 Ruby 类支持 .clone?的主要内容,如果未能解决你的问题,请参考以下文章

在 Ruby 类上定义哪种方法来为其实例提供 dup / clone?

vs支持哪些编程语言

Ruby Socket 编程

.NET 3.5 中的 CultureInfo 类支持哪些文化?

如何找出 Web 项目中支持哪些文化 -> 类 CultureInfo?

ruby中的复制 dup clone