Los documentos de Ruby paradup
decir:
En general,
clone
ydup
puede tener una semántica diferente en las clases descendientes. Mientrasclone
se usa para duplicar un objeto, incluido su estado interno,dup
generalmente usa la clase del objeto descendiente para crear la nueva instancia.
Pero cuando hago alguna prueba descubrí que en realidad son lo mismo:
class Test
attr_accessor :x
end
x = Test.new
x.x = 7
y = x.dup
z = x.clone
y.x => 7
z.x => 7
Entonces, ¿cuáles son las diferencias entre los dos métodos?
dup
y quéclone
hace, sino por qué usaría uno en lugar del otro.Respuestas:
Las subclases pueden anular estos métodos para proporcionar una semántica diferente. En
Object
sí mismo, hay dos diferencias clave.Primero,
clone
copia la clase singleton, mientrasdup
que no.En segundo lugar,
clone
conserva el estado congelado, mientrasdup
que no.La implementación de Rubinius para estos métodos es a menudo mi fuente de respuestas a estas preguntas, ya que es bastante clara y una implementación de Ruby bastante compatible.
fuente
o = Object.new; class << o; A=5; end; puts ( class << o.clone; A; end ); puts ( class << o.dup; A; end )
.extend
editado en el objeto original. EntoncesObject.new.extend(Enumerable).dup.is_a?(Enumerable)
devuelve falso.Cuando se trata de ActiveRecord también hay una diferencia significativa:
dup
crea un nuevo objeto sin que se establezca su ID, por lo que puede guardar un nuevo objeto en la base de datos presionando.save
clone
crea un nuevo objeto con la misma identificación, por lo que todos los cambios realizados en ese nuevo objeto sobrescribirán el registro original si se presiona.save
fuente
dup
yclone
métodos en miActiveRecord
objeto, obtengo resultados inversos de lo que has mencionado en la respuesta. lo que significa que cuando estoy usandodup
, crea un nuevo objeto con el que seid
está configurando y mientras lo usaclone
crea un objeto sin queid
se configure. ¿Puedes por favor mirarlo nuevamente y aclararlo? . Thnxclone
crear un nuevo registro que nunca se haya guardado debería ser bastante seguro? ¿Puedo construir un "objeto de plantilla" de esta manera y clonarlo para guardar instancias específicas?Una diferencia es con los objetos congelados. El
clone
de un objeto congelado también está congelado (mientras que eldup
de un objeto congelado no lo está).Otra diferencia es con los métodos singleton. La misma historia aquí,
dup
no copia esos, peroclone
sí.fuente
Ambos son casi idénticos, pero el clon hace una cosa más que dup. En clon, el estado congelado del objeto también se copia. En dup, siempre estará descongelado.
fuente
El documento más reciente incluye un buen ejemplo:
fuente
Puedes usar clone para hacer programación basada en prototipos en Ruby. La clase Object de Ruby define tanto el método de clonación como el método dup. Tanto clone como dup producen una copia superficial del objeto que está copiando; es decir, las variables de instancia del objeto se copian pero no los objetos a los que hacen referencia. Voy a demostrar un ejemplo:
Observe que en el ejemplo anterior, el clon naranja copia el estado (es decir, las variables de instancia) del objeto apple, pero cuando el objeto apple hace referencia a otros objetos (como el color del objeto String), esas referencias no se copian. En cambio, ¡manzana y naranja hacen referencia al mismo objeto! En nuestro ejemplo, la referencia es el objeto de cadena 'rojo'. Cuando orange usa el método append, <<, para modificar el objeto String existente, cambia el objeto string a 'red orange'. En efecto, esto también cambia apple.color, ya que ambos apuntan al mismo objeto String.
Como nota al margen, el operador de asignación, =, asignará un nuevo objeto y, por lo tanto, destruirá una referencia. Aquí hay una demostración:
En el ejemplo anterior, cuando asignamos un nuevo objeto nuevo al método de instancia de color del clon naranja, ya no hace referencia al mismo objeto que la manzana. Por lo tanto, ahora podemos modificar el método de color naranja sin afectar el método de color de apple, pero si clonamos otro objeto de apple, ese nuevo objeto hará referencia a los mismos objetos en las variables de instancia copiadas como apple.
dup también producirá una copia superficial del objeto que está copiando, y si hiciera la misma demostración que se muestra arriba a dup, verá que funciona exactamente de la misma manera. Pero hay dos diferencias principales entre clonar y dup. Primero, como otros mencionaron, clone copia el estado congelado y dup no. ¿Qué significa esto? El término 'congelado' en Ruby es un término esotérico para inmutable, que en sí mismo es una nomenclatura en informática, lo que significa que algo no puede cambiarse. Por lo tanto, un objeto congelado en Ruby no puede modificarse de ninguna manera; es, en efecto, inmutable. Si intenta modificar un objeto congelado, Ruby generará una excepción RuntimeError. Dado que clonar copia el estado congelado, si intenta modificar un objeto clonado, generará una excepción RuntimeError. Por el contrario, dado que dup no copia el estado congelado,
En segundo lugar, y, más interesante, ¡el clon copia la clase singleton (y por lo tanto sus métodos)! Esto es muy útil si desea realizar una programación basada en prototipos en Ruby. Primero, demostremos que, de hecho, los métodos singleton se copian con clon, y luego podemos aplicarlo en un ejemplo de programación basada en prototipos en Ruby.
Como puede ver, la clase singleton de la instancia del objeto de fruta se copia en el clon. Y, por lo tanto, el objeto clonado tiene acceso al método singleton: ¿sembrado ?. Pero este no es el caso con dup:
Ahora, en la programación basada en prototipos, no tiene clases que extiendan otras clases y luego cree instancias de clases cuyos métodos se derivan de una clase principal que sirve como modelo. En cambio, tiene un objeto base y luego crea un nuevo objeto a partir del objeto con sus métodos y estado copiados (por supuesto, dado que estamos haciendo copias superficiales a través de clon, cualquier objeto al que se haga referencia de variables de instancia se compartirá tal como en JavaScript prototipos). Luego puede completar o cambiar el estado del objeto completando los detalles de los métodos clonados. En el siguiente ejemplo, tenemos un objeto de fruta base. Todas las frutas tienen semillas, por lo que creamos un método number_of_seeds. Pero las manzanas tienen una semilla, por lo que creamos un clon y completamos los detalles. Ahora cuando clonamos manzana, ¡no solo clonamos los métodos sino que clonamos el estado! Recuerde que el clon hace una copia superficial del estado (variables de instancia). Y por eso, cuando clonemos una manzana para obtener una manzana roja, ¡la manzana roja automáticamente tendrá 1 semilla! Puedes pensar en red_apple como un objeto que hereda de Apple, que a su vez hereda de Fruit. Por eso, capitalicé Fruit and Apple. Eliminamos la distinción entre clases y objetos por cortesía del clon.
Por supuesto, podemos tener un método constructor en la programación basada en prototipos:
En última instancia, utilizando clone, puede obtener algo similar al comportamiento del prototipo de JavaScript.
fuente