【问题标题】:When to use dup, and when to use clone in Ruby?什么时候使用 dup,什么时候在 Ruby 中使用 clone?
【发布时间】:2012-07-29 20:21:39
【问题描述】:

What's the difference between Ruby's dup and clone methods? 描述了dupclone 的行为差异。但是什么时候应该使用dup,什么时候应该使用clone呢?

来自实际项目的示例讨论他们为什么使用 dup 而不是 clone,反之亦然,这将是这个问题的理想选择。

另外,解释一下为什么存在这两种不同的方法会很有帮助。这可能是指来自 Ruby 的创建者的声明,或者是对影响 Ruby 的语言中的 dupclone 等方法的检查。

【问题讨论】:

标签: ruby clone idioms dup


【解决方案1】:

DUP 和 CLONE 都可用于创建对象的浅表副本。两者都复制了 obj 的实例变量。但我们需要选择性地使用它们。

这些之间几乎没有区别

1) CLONE 复制对象的 FROZEN 和 TAINTED 状态,而 DUP 仅复制对象的 TAINTED 状态。

2) 使用 CLONE,您可以复制对象的任何单例方法,但 DUP 不支持。

CLONE 用于复制对象,包括其内部状态,DUP 通常使用后代对象的类来创建新实例。

我在使用 DUP 复制 ActiveRecord 行时遇到了一些痛苦的经历,这最终导致丢失了原来的行,而在 CLONE 上也可以正常工作。

当我陷入困惑时,我发现 Article of Open Source is Wide Open

【讨论】:

  • "在 Ruby 中有三种复制方式:#dup、#clone 和 '='。" - =如何复制?
  • 我没有深入了解 '=' 复制的方式,但它也会进行浅复制。这是一个good example 用于开始,但总的来说,赋值运算符不会复制值,它只是复制对对象的引用
  • 请注意:Marshal::load(Marshal.dump(foo)) 有效,但可能会导致数据库模型出现问题。
  • Operator = 不做浅拷贝,它只会拷贝对象引用!这种说法完全是错误的。另外:#dup 和#clone 之间的区别只是对冻结状态的处理。我认为为两者实现不同的复制算法是一个坏主意 - 无论是深的还是浅的。两者之间性能差异的数字在哪里?看到显着差异我会感到非常惊讶,因为两者基本相同。你能指点数字吗?
【解决方案2】:

clone 确实复制了对象的frozen 状态,而dup 没有:

o = Object.new
o.freeze

o.clone.frozen?
#=> true

o.dup.frozen?
#=> false

clone 也会复制对象的单例方法,而dup 不会:

o = Object.new
def o.foo
  42
end

o.clone.respond_to?(:foo)
#=> true

o.dup.respond_to?(:foo)
#=> false

这使我假设clone 有时被理解为提供比dup 更“深”的副本。以下是有关该主题的一些引述:

Comment on ActiveRecord::Base#initialize_dup from Rails 3:

复制的对象没有分配 id 并被视为新记录。笔记 这是一个“浅”副本,因为它复制了对象的属性 只是,不是它的关联。 “深”副本的范围是应用程序 具体的,因此留给应用程序根据 满足自己的需要。

An article about deep copies in Ruby:

还有一个方法值得一提,cloneclone 方法与 dup 做同样的事情,但有一个重要区别:预计对象将使用可以进行深度复制的方法覆盖此方法。

But then again, theres deep_dup in Rails 4:

如果对象是可复制的,则返回对象的深层副本。如果它不可复制,则返回self

and also ActiveRecord::Core#dup and #clone in Rails 4:

clone — 与 Ruby 的克隆方法相同。这是一个“浅”的副本。请注意,您的属性不会被复制。 [...] 如果您需要属性哈希的副本,请使用 #dup 方法。

这意味着这里,dup这个词再次用于指代深度克隆。据我所知,社区中似乎没有达成共识,除了当你需要任何一个特定的副作用时,你应该使用clonedup

最后,我在 Ruby 代码中看到的 dupclone 更频繁。到目前为止,我从未使用过clone,除非我明确需要,否则我不会使用。

【讨论】:

  • 现在在我看来你必须使用dup,除非你有理由使用clonedup 似乎更简单)。但也许那是因为我现在关心复制哈希。所以我不关心冻结状态和单例类。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-03-13
  • 2014-06-04
  • 2017-09-13
  • 1970-01-01
  • 2013-05-23
  • 2022-11-10
相关资源
最近更新 更多