[Ruby] Prenez l'habitude d'utiliser la méthode dup lors de la copie d'une variable chaîne

Préface

Je programme en Ruby et j'y suis accro, ou j'y suis accro, alors n'oubliez pas.

environnement

Pour le moment, les informations de version également. Mais c'est basique, donc peu importe la version.

Lors de la copie de la valeur d'une variable ...

Lorsque vous faites une copie de la valeur d'une variable, avez-vous juste à faire une affectation?

@bob = "I love you"
@carol = @bob         # <=ici!

puts "@bob = #{@bob}, @carol = #{@carol} "
    # => @bob = I love you, @carol = I love you

Lorsque vous faites une copie de la valeur d'une variable, vous avez généralement pour objectif de "conserver la valeur de la variable d'origine et d'utiliser la variable copiée pour diverses opérations". Même si la valeur de la variable copiée change et qu'elle casse, c'est correct car la variable d'origine est enregistrée.

# ---Suite ci-dessus---
@carol = @carol + ", too"
puts "@bob = #{@bob}, @carol = #{@carol} "
    # => @bob = I love you, @carol = I love you, too

Comme indiqué ci-dessus, même si vous ajoutez à la chaîne de caractères de la variable de destination d'affectation @ carol, la valeur de la variable source d'affectation @ bob ne change pas ~~ Naturellement ~~.

Toutefois, si vous effectuez une "opération destructive" telle que le remplacement de la chaîne de caractères dans la variable de destination d'affectation, la valeur de la source d'affectation sera également affectée.

@bob = "I love you"
@carol = @bob

@carol.sub!("love", "hate")

puts "@bob = #{@bob}, @carol = #{@carol} "
    # => @bob = I hate you, @carol = I hate you

J'aurais dû changer la valeur de @ carol, mais la valeur de @ bob a également changé.

La raison en est que dans Ruby, tout est un objet, et l'opérateur d'affectation "passe par référence" pour copier la ~~ destination de référence ~~ en copiant la référence d'objet. [^ 1] Si @carol = @ bob, alors @ carol et @ bob font référence au même objet chaîne. Donc, si vous faites une "opération destructrice" du côté @ carol, les deux changeront car l'objet référencé par le @ bob est le même.

Au fait, même avec la même opération, si vous la modifiez en utilisant la méthode sub au lieu de sub!, Le comportement changera à nouveau.

# ---Suite ci-dessus---
@bob = @bob.sub("hate", "love")                                                

puts "@bob = #{@bob}, @carol = #{@carol} "                                     
    # => @bob = I love you, @carol = I hate you

J'ai changé la chaîne «@ bob» en «love» de la même manière, mais «@ carol» est toujours «haine». .. .. Je te détestais bob. .. ..

Mais pourquoi?

Dans le cas de sub!, Le contenu de cet objet est modifié directement, mais dans le cas de sub, la chaîne de caractères remplacée est" générée en tant que nouvel objet "et affectée à nouveau à @ bob. Parce qu'il y a. L'objet référencé est passé de celui référencé par «@ carol» à un nouveau.

Pour la même raison, dans le premier exemple, l'ajout de ", too" à la chaîne "@ carol" n'a pas changé la valeur de "@ bob". En ajoutant une autre chaîne de caractères à la chaîne de caractères de @ carol, un" nouvel objet "de la chaîne de caractères combinée a été créé et réaffecté à @ carol, donc il est appelé @bob. C'est parce que l'objet a changé.

De cette manière, si vous êtes soulagé de penser que vous avez simplement copié la valeur par affectation, la valeur de la source d'affectation peut changer en fonction du traitement ultérieur, mais cela peut convenir en fonction de l'ordre de traitement. Qui va se passer.

Alors tu fais quoi?

Comme je l'ai écrit précédemment, la scène dans laquelle vous souhaitez copier une variable est due au fait que vous souhaitez enregistrer la valeur de la source de copie, donc je ne suppose pas que si vous modifiez la valeur de la destination de la copie, la valeur de la source de la copie changera également. C'est une mauvaise idée. Vous n'avez pas besoin de le copier si vous pouvez le modifier.

Alors que dois-je faire?

C'est pourquoi la méthode dup sort. La méthode dup est une méthode de duplication d'un objet, c'est-à-dire de création d'un autre objet avec le même contenu.

@bob = "I love you"
@carol = @bob.dup      # <==Ici dans la méthode dup@Créez un nouvel objet qui copie la valeur de bob et attribuez-le

@carol.sub!("love", "hate")

puts "@bob = #{@bob}, @carol = #{@carol} "
    # => @bob = I love you, @carol = I hate you

Cela a la même apparence, mais cette fois, seul «@ carol» a changé en «haine». Après tout, Bob est détesté. .. .. C'est parce que l'objet créé par la méthode dup est différent de l'objet que possède @ bob.

Vous pouvez utiliser la méthode ʻobject_id` pour voir si les objets correspondent.

@bob = "I love you"
@carol = @bob
puts @bob.object_id    # => 46779560
puts @carol.object_id  # => 46779560

@anna = @bob.dup
@anna.object_id        # => 46931780

Certes, si vous l'assignez tel quel, il aura le même ID d'objet, et si vous le créez avec la méthode dup, il aura un ID d'objet différent.

En faisant cela, même si la valeur est la même, il s'agit d'un objet complètement différent, donc peu importe la façon dont vous jouez avec, la valeur d'origine ne changera pas sans autorisation.

En fait, je pense qu'il y a de nombreux cas où il n'y a pas de problème avec juste «assignation» parce que l'objet change dans l'opération suivante. Cependant, il existe un risque élevé d'induire des bogues si vous l'affectez par inadvertance. Alors

Lors de la copie de variables, ne les attribuez pas, utilisez la méthode dup ou quelque chose pour dupliquer correctement

Je ferai de mon mieux pour que je puisse faire les choses inconsciemment (je me dis ...)

En outre ...

En plus de la méthode «dup», il existe une méthode «clone» pour répliquer des objets. Vous pouvez également utiliser marshal_dump, marshal_load.

Pour la duplication d'objets chaîne, «dup» est suffisant. En plus de «dup», «clone» duplique également une copie de la méthode singulière et de l'état figé de l'objet. Lors de la duplication d'un tableau, d'un hachage ou d'une classe, «dup» ou «clone» ne duplique pas les éléments ou les variables internes, ce qui est inadéquat. Dans ce cas, vous devez utiliser marshal_dump, marshal_load et remplacer la méthode si nécessaire.

Veuillez consulter l'histoire détaillée ici. (Je dois aussi étudier ...)

[^ 1]: Le mot "passer par référence" a été supprimé.

Recommended Posts