Les documents Ruby pourdup
dire:
En général,
clone
etdup
peut avoir une sémantique différente dans les classes descendantes. Whileclone
est utilisé pour dupliquer un objet, y compris son état interne,dup
utilise généralement la classe de l'objet descendant pour créer la nouvelle instance.
Mais quand je fais un test, je trouve qu'ils sont en fait les mêmes:
class Test
attr_accessor :x
end
x = Test.new
x.x = 7
y = x.dup
z = x.clone
y.x => 7
z.x => 7
Quelles sont donc les différences entre les deux méthodes?
dup
etclone
fait, mais pourquoi vous devriez utiliser un plutôt que l'autre.Réponses:
Les sous-classes peuvent remplacer ces méthodes pour fournir une sémantique différente. En
Object
soi, il existe deux différences clés.Tout d'abord,
clone
copie la classe singleton, maisdup
pas.Deuxièmement,
clone
préserve l'état gelé, tandisdup
que non.L' implémentation Rubinius pour ces méthodes est souvent ma source de réponses à ces questions, car elle est assez claire et une implémentation Ruby assez conforme.
la source
o = Object.new; class << o; A=5; end; puts ( class << o.clone; A; end ); puts ( class << o.dup; A; end )
.extend
édités sur l'objet d'origine.Object.new.extend(Enumerable).dup.is_a?(Enumerable)
Retourne donc faux.Lorsque vous traitez avec ActiveRecord, il y a aussi une différence significative:
dup
crée un nouvel objet sans que son id soit défini, vous pouvez donc enregistrer un nouvel objet dans la base de données en appuyant sur.save
clone
crée un nouvel objet avec le même identifiant, donc toutes les modifications apportées à ce nouvel objet écraseront l'enregistrement d'origine en cas de frappe.save
la source
dup
etclone
méthodes sur monActiveRecord
objet, je reçois des résultats inverses de ce que vous avez mentionné dans la réponse. ce qui signifie que lorsque j'utilisedup
, il crée un nouvel objet avec sonid
réglage et pendant son utilisationclone
crée un objet sans qu'ilid
soit défini. pouvez-vous s'il vous plaît examiner à nouveau et clearifier? . Thnxclone
ing un nouvel enregistrement qui n'a jamais été enregistré devrait être assez sûr alors? Puis-je créer un "objet modèle" de cette façon et le cloner pour enregistrer des instances spécifiques?Une différence est avec les objets gelés. Le
clone
d'un objet gelé est également gelé (contrairement à celuidup
d'un objet gelé).Une autre différence réside dans les méthodes singleton. Même histoire ici,
dup
ne les copie pas, mais leclone
fait.la source
Les deux sont presque identiques, mais le clone fait plus que dup. En clone, l'état figé de l'objet est également copié. En dup, il sera toujours décongelé.
la source
Le nouveau document comprend un bon exemple:
la source
Vous pouvez utiliser clone pour effectuer une programmation basée sur des prototypes dans Ruby. La classe Object de Ruby définit à la fois la méthode clone et la méthode dup. Le clone et le dup produisent une copie superficielle de l'objet qu'il copie; c'est-à-dire que les variables d'instance de l'objet sont copiées mais pas les objets qu'elles référencent. Je vais vous montrer un exemple:
Remarquez dans l'exemple ci-dessus, le clone orange copie l'état (c'est-à-dire les variables d'instance) de l'objet apple, mais lorsque l'objet apple référence d'autres objets (tels que la couleur de l'objet String), ces références ne sont pas copiées. Au lieu de cela, pomme et orange font référence au même objet! Dans notre exemple, la référence est l'objet chaîne "rouge". Lorsque orange utilise la méthode append <<, pour modifier l'objet String existant, il change l'objet chaîne en «orange rouge». Cela modifie également apple.color, car ils pointent tous les deux vers le même objet String.
En remarque, l'opérateur d'affectation, =, affectera un nouvel objet et détruira ainsi une référence. Voici une démonstration:
Dans l'exemple ci-dessus, lorsque nous avons affecté un nouvel objet à la méthode d'instance de couleur du clone orange, il ne fait plus référence au même objet que apple. Par conséquent, nous pouvons maintenant modifier la méthode de couleur d'orange sans affecter la méthode de couleur de pomme, mais si nous clonons un autre objet de pomme, ce nouvel objet référencera les mêmes objets dans les variables d'instance copiées que pomme.
dup produira également une copie superficielle de l'objet qu'il copie, et si vous faisiez la même démonstration ci-dessus pour dup, vous verrez que cela fonctionne exactement de la même manière. Mais il existe deux différences majeures entre clone et dup. Tout d'abord, comme d'autres l'ont mentionné, le clone copie l'état gelé et pas le dup. Qu'est-ce que ça veut dire? Le terme «gelé» en Ruby est un terme ésotérique pour immuable, qui est lui-même une nomenclature en informatique, ce qui signifie que quelque chose ne peut pas être changé. Ainsi, un objet figé dans Ruby ne peut être modifié en aucune façon; il est, en effet, immuable. Si vous essayez de modifier un objet figé, Ruby lèvera une exception RuntimeError. Étant donné que clone copie l'état figé, si vous essayez de modifier un objet cloné, il déclenchera une exception RuntimeError. Inversement, puisque dup ne copie pas l'état figé,
Deuxièmement, et, plus intéressant encore, clone copie la classe singleton (et donc ses méthodes)! Ceci est très utile si vous souhaitez entreprendre une programmation basée sur des prototypes dans Ruby. Tout d'abord, montrons qu'en effet les méthodes singleton sont copiées avec clone, puis nous pouvons l'appliquer dans un exemple de programmation basée sur des prototypes dans Ruby.
Comme vous pouvez le voir, la classe singleton de l'instance d'objet fruit est copiée dans le clone. Et donc l'objet cloné a accès à la méthode singleton: seeded ?. Mais ce n'est pas le cas avec dup:
Désormais, dans la programmation basée sur des prototypes, vous n'avez pas de classes qui étendent d'autres classes, puis créez des instances de classes dont les méthodes dérivent d'une classe parente qui sert de modèle. Au lieu de cela, vous avez un objet de base, puis vous créez un nouvel objet à partir de l'objet avec ses méthodes et son état copiés (bien sûr, puisque nous faisons des copies superficielles via un clone, tous les objets auxquels les variables d'instance font référence seront partagés comme dans JavaScript prototypes). Vous pouvez ensuite remplir ou modifier l'état de l'objet en renseignant les détails des méthodes clonées. Dans l'exemple ci-dessous, nous avons un objet fruit de base. Tous les fruits ont des graines, nous créons donc une méthode number_of_seeds. Mais les pommes ont une graine, alors nous créons un clone et remplissons les détails. Maintenant, quand nous clonons une pomme, nous avons non seulement cloné les méthodes, mais nous avons cloné l'État! N'oubliez pas que le clone effectue une copie superficielle de l'état (variables d'instance). Et à cause de cela, lorsque nous clonons une pomme pour obtenir un red_apple, red_apple aura automatiquement 1 graine! Vous pouvez penser à red_apple comme un objet qui hérite d'Apple, qui à son tour hérite de Fruit. C'est pourquoi j'ai capitalisé Fruit et Apple. Nous avons supprimé la distinction entre les classes et les objets grâce à clone.
Bien sûr, nous pouvons avoir une méthode constructeur en programmation basée sur des prototypes:
En fin de compte, en utilisant clone, vous pouvez obtenir quelque chose de similaire au comportement du prototype JavaScript.
la source