Ruby: as diferenças entre dup e clone

Você já se perguntou quais são as diferenças entre #dup e #clone em Ruby?

Ambos criam uma cópia superficial de um objeto (o que significa que eles não copiam os objetos que podem ser referenciados no objeto copiado). No entanto, #clone faz duas coisas que #dup não faz:

  • copie a classe singleton do objeto copiado
  • manter o status congelado do objeto copiado

Exemplos de métodos singleton que não estão sendo copiados.

dup:

a = Object.new
def a.foo; :foo end
p a
.foo
# => :foo
b
= a.dup
p b
.foo
# => undefined method `foo' for #<Object:0x007f8bc395ff00> (NoMethodError)

vs clone:

a = Object.new
def a.foo; :foo end
p a
.foo
# => :foo
b
= a.clone
p b
.foo
# => :foo

Estado congelado:

a = Object.new
a
.freeze
p a
.frozen?
# => true
b
= a.dup
p b
.frozen?
# => false
c
= a.clone
p c
.frozen?
# => true

Olhar para o código-fonte do Rubinius torna a diferença extremamente óbvia.

Por causa das etapas extras, clone é um pouco mais lento do que dup, mas provavelmente não é isso que tornará seu aplicativo muito lento.

Apenas uma nota rápida sobre cópias superficiais (verdadeiro para clone e dupe ). Observe como a matriz referenciada pelo atributo bar não é copiada, mas compartilhada entre as instâncias original e copiada:

class Foo
attr_accessor
:bar
def initialize
self.bar = [1,2,3]
end
end

a
= Foo.new
b
= a.clone
p a
.bar
# => [1, 2, 3]
p b
.bar
# => [1, 2, 3]
a
.bar.clear # clearing the array #bar points to
p a
.bar
# => []
p b
.bar
# => []

Ambos os objectos, um e b compartilham a mesma referência ao exemplo matriz criada quando um é iniciada. Existem algumas maneiras de fazer uma cópia profunda de um objeto, mas isso é diferente.

Para mais dicas, artigos e apresentações, consulte meu site pessoal .