I'm programming in Ruby and I'm addicted to it, or I'm addicted to it, so don't forget.
2020/09/16 11:12: The wording and sentences have been revised in response to Mr. scivola's point. (I thought it would be better to make corrections with strikethroughs so that I could see the corrections, but since there were so many corrections, I edited them directly.) If there are any strange points, I will correct them as appropriate. ..
2020/09/16 21:50: "Pass by reference" has been corrected to "Pass by reference".
2020/09/17 21:35: After a lot of trouble, I corrected the word "pass by reference" so that it is not used.
For the time being, version information as well. But it's basic, so it shouldn't be version-related.
When you make a copy of the value of a variable, do you just have to make an assignment?
@bob = "I love you"
@carol = @bob # <=here!
puts "@bob = #{@bob}, @carol = #{@carol} "
# => @bob = I love you, @carol = I love you
When you make a copy of the value of a variable, you usually have the purpose of "keeping the value of the original variable and using the copied variable for various operations". Even if the value of the copied variable changes and it breaks, the original variable is saved, so it's okay.
# ---Continued above---
@carol = @carol + ", too"
puts "@bob = #{@bob}, @carol = #{@carol} "
# => @bob = I love you, @carol = I love you, too
As shown above, even if you add to the character string to the variable @carol
of the assignment destination, the value of the variable @ bob
of the assignment source does not change ~~ Naturally ~~.
However, if you perform a "destructive operation" such as replacing the character string inside the variable of the assignment destination, the value of the assignment source will also be affected.
@bob = "I love you"
@carol = @bob
@carol.sub!("love", "hate")
puts "@bob = #{@bob}, @carol = #{@carol} "
# => @bob = I hate you, @carol = I hate you
I should have changed the value of @ carol
, but the value of @ bob
has also changed.
The reason for this is that in Ruby everything is an object, and the assignment operator is "passing by reference" which copies the ~~ reference destination ~~ copying the object reference. [^ 1]
If you say @carol = @bob
, then @carol
and @bob
refer to the same string object. So, if you do a "destructive operation" on @ carol
, both will change because the object referenced by @ bob
is the same.
By the way, even with the same operation, if you change it using the sub
method instead ofsub!
, The behavior will change again.
# ---Continued above---
@bob = @bob.sub("hate", "love")
puts "@bob = #{@bob}, @carol = #{@carol} "
# => @bob = I love you, @carol = I hate you
I changed the string @ bob
to love
in the same way, but @ carol
is still hate
. .. .. I hated you bob. .. ..
But why?
In the case of sub!
, the contents of that object are changed directly, but in the case of sub
, the replaced character string is" generated as a new object "and assigned to @ bob
again. Because there is. The referenced object has changed from the one referenced with @carol
to a new one.
For the same reason, in the first example, adding ", too" to the @ carol
string did not change the value of @ bob
. By adding another string to the @ carol
string, a" new object "of the combined string was created and reassigned to @ carol
, so it is referred to as @bob. This is because the object has changed.
In this way, if you are relieved to think that you simply copied the value by assignment, the value of the assignment source may change depending on the subsequent processing, but it may be okay depending on the processing order. Will happen.
As I wrote earlier, the situation where you want to copy a variable is because you want to save the value of the copy source, so I do not assume that if you change the value of the copy destination, the value of the copy source will also change. It's a bad thing. You don't need to copy it if you can change it.
Then what should I do?
That's why the dup
method comes out. The dup
method is a method that duplicates an object, that is, creates another object with the same contents.
@bob = "I love you"
@carol = @bob.dup # <==Here in the dup method@Create a new object that copies the value of bob and assign it
@carol.sub!("love", "hate")
puts "@bob = #{@bob}, @carol = #{@carol} "
# => @bob = I love you, @carol = I hate you
It looks the same, but this time only @carol
has changed to hate
. After all bob is hated. .. ..
This is because the object created by the dup
method is different from the object that @ bob
has.
You can use the ʻobject_id` method to see if the objects match.
@bob = "I love you"
@carol = @bob
puts @bob.object_id # => 46779560
puts @carol.object_id # => 46779560
@anna = @bob.dup
@anna.object_id # => 46931780
Certainly, if you assign it as it is, it will have the same object ID, and if you create it with the dup
method, it will have a different object ID.
By doing this, even if the value is the same, it is a completely different object, so no matter how you play with it, the original value will not change without permission.
In fact, I think that there are many cases where there is no problem with just "assignment" because the object changes in the subsequent operation. However, there is a high risk of inducing a bug if you inadvertently affect it. So
When copying variables, do not assign, use the dup method or something to duplicate properly
I will do my best so that I can do things unconsciously (I tell myself ...)
In addition to the dup
method, there is a clone
method for replicating objects. You may also use marshal_dump
, marshal_load
.
For duplication of string objects, dup
is sufficient.
In addition to dup
, clone
also duplicates a copy of the singular method and the frozen state of the object.
When duplicating arrays, hashes, and classes, dup
and clone
do not duplicate elements and internal variables, which is inadequate. In that case, you need to use marshal_dump
, marshal_load
, and override the method if necessary.
Please check the detailed story around here. (I have to study too ...)
[^ 1]: The word "pass by reference" has been removed.
Recommended Posts