Os documentos do Ruby paradup
dizer:
Em geral,
clone
edup
pode ter semântica diferente nas classes descendentes. Enquantoclone
é usado para duplicar um objeto, incluindo seu estado interno,dup
normalmente usa a classe do objeto descendente para criar a nova instância.
Mas quando faço alguns testes, descobri que eles são realmente os mesmos:
class Test
attr_accessor :x
end
x = Test.new
x.x = 7
y = x.dup
z = x.clone
y.x => 7
z.x => 7
Então, quais são as diferenças entre os dois métodos?
dup
e o queclone
faz, mas por que você usaria um e não o outro.Respostas:
As subclasses podem substituir esses métodos para fornecer semânticas diferentes. Em
Object
si, existem duas diferenças principais.Primeiro,
clone
copia a classe singleton, enquantodup
não.Segundo,
clone
preserva o estado congelado, enquantodup
não.A implementação do Rubinius para esses métodos geralmente é minha fonte de respostas para essas perguntas, pois é bastante clara e uma implementação do Ruby razoavelmente compatível.
fonte
o = Object.new; class << o; A=5; end; puts ( class << o.clone; A; end ); puts ( class << o.dup; A; end )
.extend
editados no objeto original. EntãoObject.new.extend(Enumerable).dup.is_a?(Enumerable)
retorna false.Ao lidar com o ActiveRecord, também há uma diferença significativa:
dup
cria um novo objeto sem que seu ID seja definido, para que você possa salvar um novo objeto no banco de dados pressionando.save
clone
cria um novo objeto com o mesmo ID; portanto, todas as alterações feitas nesse novo objeto substituirão o registro original se você pressionar.save
fonte
dup
eclone
métodos no meuActiveRecord
objeto, estou obtendo resultados inversos do que você mencionou na resposta. o que significa que quando estou usandodup
, ele cria um novo objeto enquanto estáid
sendo definido e, enquanto o usaclone
, cria um objeto sem que estejaid
sendo definido. você pode procurar novamente e esclarecer? . Thnxclone
um novo registro que nunca foi salvo deve ser bastante seguro, então? Posso criar um "objeto de modelo" dessa maneira e cloná-lo para salvar instâncias específicas?Uma diferença é com objetos congelados. O
clone
objeto congelado também está congelado (enquanto odup
objeto congelado não está).Outra diferença está nos métodos singleton. A mesma história aqui,
dup
não as copia, masclone
sim.fonte
Ambos são quase idênticos, mas o clone faz mais uma coisa que o dup. No clone, o estado congelado do objeto também é copiado. No dup, sempre será descongelado.
fonte
O documento mais recente inclui um bom exemplo:
fonte
Você pode usar o clone para fazer a programação baseada em protótipo no Ruby. A classe Object do Ruby define o método clone e o método dup. Tanto o clone quanto o dup produzem uma cópia superficial do objeto que está copiando; isto é, as variáveis de instância do objeto são copiadas, mas não os objetos a que se referem. Vou demonstrar um exemplo:
Observe no exemplo acima, o clone laranja copia o estado (ou seja, as variáveis de instância) do objeto apple, mas onde o objeto apple faz referência a outros objetos (como a cor do objeto String), essas referências não são copiadas. Em vez disso, maçã e laranja fazem referência ao mesmo objeto! No nosso exemplo, a referência é o objeto de string 'red'. Quando orange usa o método append, <<, para modificar o objeto String existente, ele muda o objeto de string para 'laranja vermelho'. Isso também altera apple.color, pois ambos apontam para o mesmo objeto String.
Como observação lateral, o operador de atribuição, =, atribuirá um novo objeto e, assim, destruirá uma referência. Aqui está uma demonstração:
No exemplo acima, quando atribuímos um novo objeto novo ao método de instância de cor do clone laranja, ele não faz mais referência ao mesmo objeto que a maçã. Portanto, agora podemos modificar o método de cor laranja sem afetar o método de cor da maçã, mas se clonarmos outro objeto da maçã, esse novo objeto fará referência aos mesmos objetos nas variáveis de instância copiadas da maçã.
O dup também produzirá uma cópia superficial do objeto que está copiando e, se você fizer a mesma demonstração mostrada acima no dup, verá que ele funciona exatamente da mesma maneira. Mas existem duas grandes diferenças entre clone e dup. Primeiro, como outros mencionados, o clone copia o estado congelado e o dup não. O que isto significa? O termo 'congelado' em Ruby é um termo esotérico para imutável, que por si só é uma nomenclatura na ciência da computação, o que significa que algo não pode ser mudado. Portanto, um objeto congelado no Ruby não pode ser modificado de forma alguma; é, de fato, imutável. Se você tentar modificar um objeto congelado, o Ruby gerará uma exceção RuntimeError. Como o clone copia o estado congelado, se você tentar modificar um objeto clonado, ele gerará uma exceção RuntimeError. Por outro lado, como o dup não copia o estado congelado,
Segundo, e, mais interessante, o clone copia a classe singleton (e, portanto, seus métodos)! Isso é muito útil se você deseja realizar uma programação baseada em protótipo no Ruby. Primeiro, vamos mostrar que, de fato, os métodos singleton são copiados com o clone e, em seguida, podemos aplicá-lo em um exemplo de programação baseada em protótipo no Ruby.
Como você pode ver, a classe singleton da instância do objeto fruit é copiada para o clone. E, portanto, o objeto clonado tem acesso ao método singleton: seeded ?. Mas este não é o caso do dup:
Agora, na programação baseada em protótipo, você não possui classes que estendem outras classes e, em seguida, criam instâncias de classes cujos métodos derivam de uma classe pai que serve como um blueprint. Em vez disso, você tem um objeto base e, em seguida, cria um novo objeto com seus métodos e estado copiados (é claro, como estamos fazendo cópias rasas via clone, todos os objetos aos quais as variáveis de instância referenciam serão compartilhados como no JavaScript protótipos). Você pode preencher ou alterar o estado do objeto preenchendo os detalhes dos métodos clonados. No exemplo abaixo, temos um objeto base de frutas. Como todas as frutas têm sementes, criamos um método number_of_seeds. Mas as maçãs têm uma semente e, por isso, criamos um clone e preenchemos os detalhes. Agora, quando clonamos a maçã, não apenas clonamos os métodos, mas clonamos o estado! Lembre-se de que o clone faz uma cópia superficial do estado (variáveis de instância). E por isso, quando clonamos a maçã para obter uma maçã vermelha, a maçã vermelha automaticamente terá 1 semente! Você pode pensar em red_apple como um objeto que herda da Apple, que por sua vez herda de Fruit. Por isso, capitalizei Fruit e Apple. Acabamos com a distinção entre classes e objetos, cortesia do clone.
Obviamente, podemos ter um método construtor em programação baseada em protoype:
Por fim, usando o clone, você pode obter algo semelhante ao comportamento do protótipo JavaScript.
fonte