@user.update_languages(params[:language][:language1],
params[:language][:language2],
params[:language][:language3])
lang_errors = @user.errors
logger.debug "--------------------LANG_ERRORS----------101-------------"
+ lang_errors.full_messages.inspect
if params[:user]
@user.state = params[:user][:state]
success = success & @user.save
end
logger.debug "--------------------LANG_ERRORS-------------102----------"
+ lang_errors.full_messages.inspect
if lang_errors.full_messages.empty?
@user
object adds errors to the lang_errors
variable in the update_lanugages
method. when I perform a save on the @user
object I lose the errors that were initially stored in the lang_errors
variable.
@user对象在update_lanugages方法中向lang_errors变量添加错误。当我对@user对象执行保存时,我丢失了最初存储在lang_errors变量中的错误。
Though what I am attempting to do would be more of a hack (which does not seem to be working). I would like to understand why the variable values are washed out. I understand pass by reference so I would like to know how the value can be held in that variable without being washed out.
尽管我正在尝试做的事情更多的是一种黑客行为(这似乎并不奏效)。我想知道为什么变量值被洗掉了。我理解通过引用传递,所以我想知道如何在不被清洗的情况下将值保存在该变量中。
12 个解决方案
#1
217
In traditional terminology, Ruby is strictly pass-by-value. But that's not really what you're asking here.
在传统的术语中,Ruby是严格按值传递的。但这不是你要问的问题。
Ruby doesn't have any concept of a pure, non-reference value, so you certainly can't pass one to a method. Variables are always references to objects. In order to get an object that won't change out from under you, you need to dup or clone the object you're passed, thus giving an object that nobody else has a reference to. (Even this isn't bulletproof, though — both of the standard cloning methods do a shallow copy, so the instance variables of the clone still point to the same objects that the originals did. If the objects referenced by the ivars mutate, that will still show up in the copy, since it's referencing the same objects.)
Ruby没有任何纯的、非引用值的概念,所以您当然不能将一个值传递给一个方法。变量总是引用对象。为了获得一个不会从您下面更改的对象,您需要对传递的对象进行获取或克隆,从而提供一个其他人没有引用的对象。(即便如此,这也不是防弹的——两种标准的克隆方法都只做一个浅拷贝,因此克隆的实例变量仍然指向与原来相同的对象。如果ivars引用的对象发生突变,它仍然会出现在副本中,因为它引用的是相同的对象。
#2
387
The other answerers are all correct, but a friend asked me to explain this to him and what it really boils down to is how Ruby handles variables, so I thought I would share some simple pictures / explanations I wrote for him (apologies for the length and probably some oversimplification):
其他回答者都是正确的,但是一个朋友问我跟他解释这个,它真正归结为Ruby如何处理变量,所以我想分享一些简单的图片/解释我为他写的长度,可能一些简化(道歉):
Q1: What happens when you assign a new variable str
to a value of 'foo'
?
str = 'foo'
str.object_id # => 2000
A: A label called str
is created that points at the object 'foo'
, which for the state of this Ruby interpreter happens to be at memory location 2000
.
Q2: What happens when you assign the existing variable str
to a new object using =
?
str = 'bar'.tap{|b| puts "bar: #{b.object_id}"} # bar: 2002
str.object_id # => 2002
A: The label str
now points to a different object.
Q3: What happens when you assign a new variable =
to str
?
str2 = str
str2.object_id # => 2002
A: A new label called str2
is created that points at the same object as str
.
Q4: What happens if the object referenced by str
and str2
gets changed?
str2.replace 'baz'
str2 # => 'baz'
str # => 'baz'
str.object_id # => 2002
str2.object_id # => 2002
A: Both labels still point at the same object, but that object itself has mutated (its contents have changed to be something else).
How does this relate to the original question?
It's basically the same as what happens in Q3/Q4; the method gets its own private copy of the variable / label (str2
) that gets passed in to it (str
). It can't change which object the label str
points to, but it can change the contents of the object that they both reference to contain else:
这和Q3/Q4的情况基本相同;方法获取自己的变量/标签(str2)的私有副本,并将其传递给它(str)。它不能改变标签str指向的对象,但是它可以改变它们都引用的对象的内容来包含else:
str = 'foo'
def mutate(str2)
puts "str2: #{str2.object_id}"
str2.replace 'bar'
str2 = 'baz'
puts "str2: #{str2.object_id}"
end
str.object_id # => 2004
mutate(str) # str2: 2004, str2: 2006
str # => "bar"
str.object_id # => 2004
#3
46
Is Ruby pass by reference or by value?
Ruby是通过引用传递还是通过值传递?
Ruby is pass-by-value. Always. No exceptions. No ifs. No buts.
Ruby是按值传递。总是这样。没有例外。没有如果。少啰嗦
Here is a simple program which demonstrates that fact:
这里有一个简单的程序来证明这个事实:
def foo(bar)
bar = 'reference'
end
baz = 'value'
foo(baz)
puts "Ruby is pass-by-#{baz}"
# Ruby is pass-by-value
#4
36
Ruby uses "pass by object reference"
(Using Python's terminology.)
(使用Python的术语。)
To say Ruby uses "pass by value" or "pass by reference" isn't really descriptive enough to be helpful. I think as most people know it these days, that terminology ("value" vs "reference") comes from C++.
说Ruby使用“pass by value”或“pass by reference”并不能真正说明问题。我想现在大多数人都知道这个术语(“value”vs“reference”)来自c++。
In C++, "pass by value" means the function gets a copy of the variable and any changes to the copy don't change the original. That's true for objects too. If you pass an object variable by value then the whole object (including all of its members) get copied and any changes to the members don't change those members on the original object. (It's different if you pass a pointer by value but Ruby doesn't have pointers anyway, AFAIK.)
在c++中,“传递值”意味着函数获得变量的副本,对副本的任何更改都不会更改原来的副本。对物体也是如此。如果您通过值传递一个对象变量,那么整个对象(包括所有成员)都会被复制,并且成员的任何更改都不会更改原始对象上的成员。(按值传递指针是不同的,但是Ruby无论如何都没有指针,AFAIK)。
class A {
public:
int x;
};
void inc(A arg) {
arg.x++;
printf("in inc: %d\n", arg.x); // => 6
}
void inc(A* arg) {
arg->x++;
printf("in inc: %d\n", arg->x); // => 1
}
int main() {
A a;
a.x = 5;
inc(a);
printf("in main: %d\n", a.x); // => 5
A* b = new A;
b->x = 0;
inc(b);
printf("in main: %d\n", b->x); // => 1
return 0;
}
Output:
输出:
in inc: 6
in main: 5
in inc: 1
in main: 1
In C++, "pass by reference" means the function gets access to the original variable. It can assign a whole new literal integer and the original variable will then have that value too.
在c++中,“通过引用传递”意味着函数可以访问原始变量。它可以分配一个新的整数值,原始变量也会有这个值。
void replace(A &arg) {
A newA;
newA.x = 10;
arg = newA;
printf("in replace: %d\n", arg.x);
}
int main() {
A a;
a.x = 5;
replace(a);
printf("in main: %d\n", a.x);
return 0;
}
Output:
输出:
in replace: 10
in main: 10
Ruby uses pass by value (in the C++ sense) if the argument is not an object. But in Ruby everything is an object, so there really is no pass by value in the C++ sense in Ruby.
如果参数不是对象,Ruby使用pass by值(在c++意义上)。但是在Ruby中,所有东西都是对象,所以在Ruby中,c++的意思是不存在值传递。
In Ruby, "pass by object reference" (to use Python's terminology) is used:
在Ruby中,使用“传递对象引用”(使用Python的术语):
- Inside the function, any of the object's members can have new values assigned to them and these changes will persist after the function returns.*
- 在函数中,对象的任何成员都可以为其分配新的值,这些更改将在函数返回后继续存在
- Inside the function, assigning a whole new object to the variable causes the variable to stop referencing the old object. But after the function returns, the original variable will still reference the old object.
- 在函数内部,为变量分配一个全新的对象会导致变量停止引用旧的对象。但是在函数返回后,原始变量仍然引用旧的对象。
Therefore Ruby does not use "pass by reference" in the C++ sense. If it did, then assigning a new object to a variable inside a function would cause the old object to be forgotten after the function returned.
因此Ruby在c++中不使用“传递引用”。如果它这样做了,那么将一个新对象分配给函数中的一个变量将导致在函数返回后忘记旧对象。
class A
attr_accessor :x
end
def inc(arg)
arg.x += 1
puts arg.x
end
def replace(arg)
arg = A.new
arg.x = 3
puts arg.x
end
a = A.new
a.x = 1
puts a.x # 1
inc a # 2
puts a.x # 2
replace a # 3
puts a.x # 2
puts ''
def inc_var(arg)
arg += 1
puts arg
end
b = 1 # Even integers are objects in Ruby
puts b # 1
inc_var b # 2
puts b # 1
Output:
输出:
1
2
2
3
2
1
2
1
* This is why, in Ruby, if you want to modify an object inside a function but forget those changes when the function returns, then you must explicitly make a copy of the object before making your temporary changes to the copy.
这就是为什么在Ruby中,如果你想在函数中修改一个对象,但是在函数返回时忘记这些修改,那么你必须在对该对象进行临时更改之前显式地复制该对象。
#5
16
There are already some great answers, but I want to post the definition of a pair of authorities on the subject, but also hoping someone might explain what said authorities Matz (creator of Ruby) and David Flanagan meant in their excellent O'Reilly book, The Ruby Programming Language.
已经有了一些很好的答案,但是我想把这两个权威的定义发布在这个主题上,但同时也希望有人能解释为什么说官方的Matz (Ruby的创造者)和David Flanagan在他们优秀的O'Reilly书籍,Ruby编程语言。
[from 3.8.1: Object References]
(从3.8.1对象引用):
When you pass an object to a method in Ruby, it is an object reference that is passed to the method. It is not the object itself, and it is not a reference to the reference to the object. Another way to say this is that method arguments are passed by value rather than by reference, but that the values passed are object references.
当您将对象传递给Ruby中的方法时,它是传递给方法的对象引用。它不是对象本身,也不是对对象引用的引用。另一种说法是方法参数是通过值而不是引用传递的,但是传递的值是对象引用。
Because object references are passed to methods, methods can use those references to modify the underlying object. These modifications are then visible when the method returns.
因为对象引用被传递给方法,所以方法可以使用这些引用来修改底层对象。当方法返回时,这些修改是可见的。
This all makes sense to me until that last paragraph, and especially that last sentence. This is at best misleading, and at worse confounding. How, in any way, could modifications to that passed-by-value reference change the underlying object?
直到最后一段,尤其是最后一句,我才明白这一切。这充其量是误导,更糟糕的是混淆视听。对按值传递的引用的修改如何以任何方式更改底层对象?
#6
14
Is Ruby pass by reference or by value?
Ruby是通过引用传递还是通过值传递?
Ruby is pass-by-reference. Always. No exceptions. No ifs. No buts.
Ruby是引用传递。总是这样。没有例外。没有如果。少啰嗦
Here is a simple program which demonstrates that fact:
这里有一个简单的程序来证明这个事实:
def foo(bar)
bar.object_id
end
baz = 'value'
puts "#{baz.object_id} Ruby is pass-by-reference #{foo(baz)} because object_id's (memory addresses) are always the same ;)"
=> 2279146940 Ruby is pass-by-reference 2279146940 because object_id's (memory addresses) are always the same ;)
=> 2279146940 Ruby是引用传递2279146940,因为object_id(内存地址)总是相同的;
def bar(babar)
babar.replace("reference")
end
bar(baz)
puts "some people don't realize it's reference because local assignment can take precedence, but it's clearly pass-by-#{baz}"
=> some people don't realize it's reference because local assignment can take precedence, but it's clearly pass-by-reference
=>有些人没有意识到它是引用,因为局部赋值可以优先,但它显然是引用传递
#7
14
Ruby is pass-by-value in a strict sense, BUT the values are references.
Ruby是严格意义上的按值传递,但值是引用。
This could be called "pass-reference-by-value". This article has the best explanation I have read: http://robertheaton.com/2014/07/22/is-ruby-pass-by-reference-or-pass-by-value/
这可以称为“按值传递引用”。这篇文章有我读过的最好的解释:http://robertheaton.com/2014/07/22/is-ruby-pass-by-reference-or-pass-by-value/
Pass-reference-by-value could briefly be explained as follows:
按值传递参照可以简单地解释如下:
A function receives a reference to (and will access) the same object in memory as used by the caller. However, it does not receive the box that the caller is storing this object in; as in pass-value-by-value, the function provides its own box and creates a new variable for itself.
函数接收对内存中调用者使用的相同对象的引用(并将访问)。但是,它没有接收到调用者正在将该对象存储在的框;就像在传递值中一样,函数提供了自己的框,并为自己创建了一个新的变量。
The resulting behavior is actually a combination of the classical definitions of pass-by-reference and pass-by-value.
结果的行为实际上是引用传递和值传递的经典定义的组合。
#8
8
Parameters are a copy of the original reference. So, you can change values, but cannot change the original reference.
参数是原始引用的副本。因此,您可以更改值,但不能更改原始引用。
#9
1
Ruby is interpreted. Variables are references to data, but not the data itself. This facilitates using the same variable for data of different types.
Ruby是解释。变量是对数据的引用,而不是数据本身。这便于对不同类型的数据使用相同的变量。
Assignment of lhs = rhs then copies the reference on the rhs, not the data. This differs in other languages, such as C, where assignment does a data copy to lhs from rhs.
lhs的赋值等于rhs,然后拷贝rhs上的引用,而不是数据。这在其他语言中是不同的,比如C,在这里,赋值从rhs中复制到lhs。
So for the function call, the variable passed, say x, is indeed copied into a local variable in the function, but x is a reference. There will then be two copies of the reference, both referencing the same data. One will be in the caller, one in the function.
对于函数调用,传递的变量,比如x,确实被复制到函数的局部变量中,但是x是一个引用。然后将有两个引用副本,都引用相同的数据。一个在调用者,一个在函数中。
Assignment in the function would then copy a new reference to the function's version of x. After this the caller's version of x remains unchanged. It is still a reference to the original data.
然后,函数中的赋值将复制一个新的引用到函数的x版本,在此之后,调用者的x版本将保持不变。它仍然是对原始数据的引用。
In contrast, using the .replace method on x will cause ruby to do a data copy. If replace is used before any new assignments then indeed the caller will see the data change in its version also.
相反,在x上使用.replace方法将导致ruby进行数据复制。如果在任何新赋值之前使用了replace,那么调用者也将看到其版本中的数据更改。
Similarly, as long as the original reference is in tact for the passed in variable, the instance variables will be the same that the caller sees. Within the framework of an object, the instance variables always have the most up to date reference values, whether those are provided by the caller or set in the function the class was passed in to.
类似地,只要原始引用对于传入的变量是熟练的,那么实例变量将与调用者看到的相同。在对象的框架中,实例变量总是具有最新的引用值,无论这些值是由调用者提供的,还是在传递给类的函数中设置的。
The 'call by value' or 'call by reference' is muddled here because of confusion over '=' In compiled languages '=' is a data copy. Here in this interpreted language '=' is a reference copy. In the example you have the reference passed in followed by a reference copy though '=' that clobbers the original passed in reference, and then people talking about it as though '=' were a data copy.
这里的“按值调用”或“按引用调用”是混乱的,因为编译语言中的“=”是一个数据副本。这里的解释语言'='是一个参考副本。在这个例子中,引用传递了一个引用副本,尽管“=”这个词是引用的原始版本,然后人们谈论它就好像“=”是一个数据副本。
To be consistent with definitions we must keep with '.replace' as it is a data copy. From the perspective of '.replace' we see that this is indeed pass by reference. Furthermore, if we walk through in the debugger, we see references being passed in, as variables are references.
为了与定义保持一致,我们必须遵守'。替换为数据拷贝。从…的角度。替换“我们看到这确实是通过引用传递的”。此外,如果我们在调试器中遍历,我们会看到正在传入的引用,因为变量是引用。
However if we must keep '=' as a frame of reference, then indeed we do get to see the passed in data up until an assignment, and then we don't get to see it anymore after assignment while the caller's data remains unchanged. At a behavioral level this is pass by value as long as we don't consider the passed in value to be composite - as we won't be able to keep part of it while changing the other part in a single assignment (as that assignment changes the reference and the original goes out of scope). There will also be a wart, in that instance variables in objects will be references, as are all variables. Hence we will be forced to talk about passing 'references by value' and have to use related locutions.
但是,如果我们必须将'='作为一个参考框架,那么我们确实可以在赋值之前看到传入的数据,然后在赋值之后,当调用者的数据保持不变时,我们就不会再看到它了。在行为层面上,这是按值传递,只要我们不认为传入值组合,我们将无法保持它的一部分而改变另一部分在一个任务(任务变化的参考和原始超出范围)。也会有一个疣,在那个实例变量中,对象将是引用,所有的变量都是。因此,我们将*谈论通过“价值参考”,并使用相关的对话。
#10
1
Try this:--
试试这个:——
1.object_id
#=> 3
2.object_id
#=> 5
a = 1
#=> 1
a.object_id
#=> 3
b = 2
#=> 2
b.object_id
#=> 5
identifier a contains object_id 3 for value object 1 and identifier b contains object_id 5 for value object 2.
标识符a包含值对象1的object_id 3,标识符b包含值对象2的object_id 5。
Now do this:--
现在这样做:—
a.object_id = 5
#=> error
a = b
#value(object_id) at b copies itself as value(object_id) at a. value object 2 has object_id 5
#=> 2
a.object_id
#=> 5
Now, a and b both contain same object_id 5 which refers to value object 2. So, Ruby variable contains object_ids to refer to value objects.
现在,a和b都包含相同的object_id 5,它指的是值对象2。因此,Ruby变量包含object_ids来引用值对象。
Doing following also gives error:--
这样做也会产生错误:——
c
#=> error
but doing this won't give error:--
但这样做不会出错:。
5.object_id
#=> 11
c = 5
#=> value object 5 provides return type for variable c and saves 5.object_id i.e. 11 at c
#=> 5
c.object_id
#=> 11
a = c.object_id
#=> object_id of c as a value object changes value at a
#=> 11
11.object_id
#=> 23
a.object_id == 11.object_id
#=> true
a
#=> Value at a
#=> 11
Here identifier a returns value object 11 whose object id is 23 i.e. object_id 23 is at identifier a, Now we see an example by using method.
这里的标识符a返回值对象11,其对象id为23,即object_id 23位于标识符a,现在我们通过使用方法看到一个示例。
def foo(arg)
p arg
p arg.object_id
end
#=> nil
11.object_id
#=> 23
x = 11
#=> 11
x.object_id
#=> 23
foo(x)
#=> 11
#=> 23
arg in foo is assigned with return value of x. It clearly shows that argument is passed by value 11, and value 11 being itself an object has unique object id 23.
在foo中的arg被赋值为x的返回值,它清楚地显示了参数是通过值11传递的,而value 11本身是一个对象,它有唯一的对象id 23。
Now see this also:--
现在看到这也:—
def foo(arg)
p arg
p arg.object_id
arg = 12
p arg
p arg.object_id
end
#=> nil
11.object_id
#=> 23
x = 11
#=> 11
x.object_id
#=> 23
foo(x)
#=> 11
#=> 23
#=> 12
#=> 25
x
#=> 11
x.object_id
#=> 23
Here, identifier arg first contains object_id 23 to refer 11 and after internal assignment with value object 12, it contains object_id 25. But it does not change value referenced by identifier x used in calling method.
在这里,标识符arg首先包含object_id 23以引用11,在使用值对象12进行内部赋值之后,它包含object_id 25。但它不改变在调用方法中使用的标识符x引用的值。
Hence, Ruby is pass by value and Ruby variables do not contain values but do contain reference to value object.
因此,Ruby是按值传递的,而Ruby变量不包含值,而是包含对值对象的引用。
#11
1
It should be noted that you do not have to even use the "replace" method to change the value original value. If you assign one of the hash values for a hash, you are changing the original value.
需要注意的是,您甚至不需要使用“replace”方法来更改原始值。如果您为散列分配了一个散列值,那么您将改变原来的值。
def my_foo(a_hash)
a_hash["test"]="reference"
end;
hash = {"test"=>"value"}
my_foo(hash)
puts "Ruby is pass-by-#{hash["test"]}"
#12
1
Two references refer to same object as long as there is no reassignment.
Any updates in the same object won't make the references to new memory since it still is in same memory. Here are few examples :
同一对象中的任何更新都不会对新内存进行引用,因为它仍然在同一内存中。这里有几个例子:
a = "first string"
b = a
b.upcase!
=> FIRST STRING
a
=> FIRST STRING
b = "second string"
a
=> FIRST STRING
hash = {first_sub_hash: {first_key: "first_value"}}
first_sub_hash = hash[:first_sub_hash]
first_sub_hash[:second_key] = "second_value"
hash
=> {first_sub_hash: {first_key: "first_value", second_key: "second_value"}}
def change(first_sub_hash)
first_sub_hash[:third_key] = "third_value"
end
change(first_sub_hash)
hash
=> {first_sub_hash: {first_key: "first_value", second_key: "second_value", third_key: "third_value"}}
#1
217
In traditional terminology, Ruby is strictly pass-by-value. But that's not really what you're asking here.
在传统的术语中,Ruby是严格按值传递的。但这不是你要问的问题。
Ruby doesn't have any concept of a pure, non-reference value, so you certainly can't pass one to a method. Variables are always references to objects. In order to get an object that won't change out from under you, you need to dup or clone the object you're passed, thus giving an object that nobody else has a reference to. (Even this isn't bulletproof, though — both of the standard cloning methods do a shallow copy, so the instance variables of the clone still point to the same objects that the originals did. If the objects referenced by the ivars mutate, that will still show up in the copy, since it's referencing the same objects.)
Ruby没有任何纯的、非引用值的概念,所以您当然不能将一个值传递给一个方法。变量总是引用对象。为了获得一个不会从您下面更改的对象,您需要对传递的对象进行获取或克隆,从而提供一个其他人没有引用的对象。(即便如此,这也不是防弹的——两种标准的克隆方法都只做一个浅拷贝,因此克隆的实例变量仍然指向与原来相同的对象。如果ivars引用的对象发生突变,它仍然会出现在副本中,因为它引用的是相同的对象。
#2
387
The other answerers are all correct, but a friend asked me to explain this to him and what it really boils down to is how Ruby handles variables, so I thought I would share some simple pictures / explanations I wrote for him (apologies for the length and probably some oversimplification):
其他回答者都是正确的,但是一个朋友问我跟他解释这个,它真正归结为Ruby如何处理变量,所以我想分享一些简单的图片/解释我为他写的长度,可能一些简化(道歉):
Q1: What happens when you assign a new variable str
to a value of 'foo'
?
str = 'foo'
str.object_id # => 2000
A: A label called str
is created that points at the object 'foo'
, which for the state of this Ruby interpreter happens to be at memory location 2000
.
Q2: What happens when you assign the existing variable str
to a new object using =
?
str = 'bar'.tap{|b| puts "bar: #{b.object_id}"} # bar: 2002
str.object_id # => 2002
A: The label str
now points to a different object.
Q3: What happens when you assign a new variable =
to str
?
str2 = str
str2.object_id # => 2002
A: A new label called str2
is created that points at the same object as str
.
Q4: What happens if the object referenced by str
and str2
gets changed?
str2.replace 'baz'
str2 # => 'baz'
str # => 'baz'
str.object_id # => 2002
str2.object_id # => 2002
A: Both labels still point at the same object, but that object itself has mutated (its contents have changed to be something else).
How does this relate to the original question?
It's basically the same as what happens in Q3/Q4; the method gets its own private copy of the variable / label (str2
) that gets passed in to it (str
). It can't change which object the label str
points to, but it can change the contents of the object that they both reference to contain else:
这和Q3/Q4的情况基本相同;方法获取自己的变量/标签(str2)的私有副本,并将其传递给它(str)。它不能改变标签str指向的对象,但是它可以改变它们都引用的对象的内容来包含else:
str = 'foo'
def mutate(str2)
puts "str2: #{str2.object_id}"
str2.replace 'bar'
str2 = 'baz'
puts "str2: #{str2.object_id}"
end
str.object_id # => 2004
mutate(str) # str2: 2004, str2: 2006
str # => "bar"
str.object_id # => 2004
#3
46
Is Ruby pass by reference or by value?
Ruby是通过引用传递还是通过值传递?
Ruby is pass-by-value. Always. No exceptions. No ifs. No buts.
Ruby是按值传递。总是这样。没有例外。没有如果。少啰嗦
Here is a simple program which demonstrates that fact:
这里有一个简单的程序来证明这个事实:
def foo(bar)
bar = 'reference'
end
baz = 'value'
foo(baz)
puts "Ruby is pass-by-#{baz}"
# Ruby is pass-by-value
#4
36
Ruby uses "pass by object reference"
(Using Python's terminology.)
(使用Python的术语。)
To say Ruby uses "pass by value" or "pass by reference" isn't really descriptive enough to be helpful. I think as most people know it these days, that terminology ("value" vs "reference") comes from C++.
说Ruby使用“pass by value”或“pass by reference”并不能真正说明问题。我想现在大多数人都知道这个术语(“value”vs“reference”)来自c++。
In C++, "pass by value" means the function gets a copy of the variable and any changes to the copy don't change the original. That's true for objects too. If you pass an object variable by value then the whole object (including all of its members) get copied and any changes to the members don't change those members on the original object. (It's different if you pass a pointer by value but Ruby doesn't have pointers anyway, AFAIK.)
在c++中,“传递值”意味着函数获得变量的副本,对副本的任何更改都不会更改原来的副本。对物体也是如此。如果您通过值传递一个对象变量,那么整个对象(包括所有成员)都会被复制,并且成员的任何更改都不会更改原始对象上的成员。(按值传递指针是不同的,但是Ruby无论如何都没有指针,AFAIK)。
class A {
public:
int x;
};
void inc(A arg) {
arg.x++;
printf("in inc: %d\n", arg.x); // => 6
}
void inc(A* arg) {
arg->x++;
printf("in inc: %d\n", arg->x); // => 1
}
int main() {
A a;
a.x = 5;
inc(a);
printf("in main: %d\n", a.x); // => 5
A* b = new A;
b->x = 0;
inc(b);
printf("in main: %d\n", b->x); // => 1
return 0;
}
Output:
输出:
in inc: 6
in main: 5
in inc: 1
in main: 1
In C++, "pass by reference" means the function gets access to the original variable. It can assign a whole new literal integer and the original variable will then have that value too.
在c++中,“通过引用传递”意味着函数可以访问原始变量。它可以分配一个新的整数值,原始变量也会有这个值。
void replace(A &arg) {
A newA;
newA.x = 10;
arg = newA;
printf("in replace: %d\n", arg.x);
}
int main() {
A a;
a.x = 5;
replace(a);
printf("in main: %d\n", a.x);
return 0;
}
Output:
输出:
in replace: 10
in main: 10
Ruby uses pass by value (in the C++ sense) if the argument is not an object. But in Ruby everything is an object, so there really is no pass by value in the C++ sense in Ruby.
如果参数不是对象,Ruby使用pass by值(在c++意义上)。但是在Ruby中,所有东西都是对象,所以在Ruby中,c++的意思是不存在值传递。
In Ruby, "pass by object reference" (to use Python's terminology) is used:
在Ruby中,使用“传递对象引用”(使用Python的术语):
- Inside the function, any of the object's members can have new values assigned to them and these changes will persist after the function returns.*
- 在函数中,对象的任何成员都可以为其分配新的值,这些更改将在函数返回后继续存在
- Inside the function, assigning a whole new object to the variable causes the variable to stop referencing the old object. But after the function returns, the original variable will still reference the old object.
- 在函数内部,为变量分配一个全新的对象会导致变量停止引用旧的对象。但是在函数返回后,原始变量仍然引用旧的对象。
Therefore Ruby does not use "pass by reference" in the C++ sense. If it did, then assigning a new object to a variable inside a function would cause the old object to be forgotten after the function returned.
因此Ruby在c++中不使用“传递引用”。如果它这样做了,那么将一个新对象分配给函数中的一个变量将导致在函数返回后忘记旧对象。
class A
attr_accessor :x
end
def inc(arg)
arg.x += 1
puts arg.x
end
def replace(arg)
arg = A.new
arg.x = 3
puts arg.x
end
a = A.new
a.x = 1
puts a.x # 1
inc a # 2
puts a.x # 2
replace a # 3
puts a.x # 2
puts ''
def inc_var(arg)
arg += 1
puts arg
end
b = 1 # Even integers are objects in Ruby
puts b # 1
inc_var b # 2
puts b # 1
Output:
输出:
1
2
2
3
2
1
2
1
* This is why, in Ruby, if you want to modify an object inside a function but forget those changes when the function returns, then you must explicitly make a copy of the object before making your temporary changes to the copy.
这就是为什么在Ruby中,如果你想在函数中修改一个对象,但是在函数返回时忘记这些修改,那么你必须在对该对象进行临时更改之前显式地复制该对象。
#5
16
There are already some great answers, but I want to post the definition of a pair of authorities on the subject, but also hoping someone might explain what said authorities Matz (creator of Ruby) and David Flanagan meant in their excellent O'Reilly book, The Ruby Programming Language.
已经有了一些很好的答案,但是我想把这两个权威的定义发布在这个主题上,但同时也希望有人能解释为什么说官方的Matz (Ruby的创造者)和David Flanagan在他们优秀的O'Reilly书籍,Ruby编程语言。
[from 3.8.1: Object References]
(从3.8.1对象引用):
When you pass an object to a method in Ruby, it is an object reference that is passed to the method. It is not the object itself, and it is not a reference to the reference to the object. Another way to say this is that method arguments are passed by value rather than by reference, but that the values passed are object references.
当您将对象传递给Ruby中的方法时,它是传递给方法的对象引用。它不是对象本身,也不是对对象引用的引用。另一种说法是方法参数是通过值而不是引用传递的,但是传递的值是对象引用。
Because object references are passed to methods, methods can use those references to modify the underlying object. These modifications are then visible when the method returns.
因为对象引用被传递给方法,所以方法可以使用这些引用来修改底层对象。当方法返回时,这些修改是可见的。
This all makes sense to me until that last paragraph, and especially that last sentence. This is at best misleading, and at worse confounding. How, in any way, could modifications to that passed-by-value reference change the underlying object?
直到最后一段,尤其是最后一句,我才明白这一切。这充其量是误导,更糟糕的是混淆视听。对按值传递的引用的修改如何以任何方式更改底层对象?
#6
14
Is Ruby pass by reference or by value?
Ruby是通过引用传递还是通过值传递?
Ruby is pass-by-reference. Always. No exceptions. No ifs. No buts.
Ruby是引用传递。总是这样。没有例外。没有如果。少啰嗦
Here is a simple program which demonstrates that fact:
这里有一个简单的程序来证明这个事实:
def foo(bar)
bar.object_id
end
baz = 'value'
puts "#{baz.object_id} Ruby is pass-by-reference #{foo(baz)} because object_id's (memory addresses) are always the same ;)"
=> 2279146940 Ruby is pass-by-reference 2279146940 because object_id's (memory addresses) are always the same ;)
=> 2279146940 Ruby是引用传递2279146940,因为object_id(内存地址)总是相同的;
def bar(babar)
babar.replace("reference")
end
bar(baz)
puts "some people don't realize it's reference because local assignment can take precedence, but it's clearly pass-by-#{baz}"
=> some people don't realize it's reference because local assignment can take precedence, but it's clearly pass-by-reference
=>有些人没有意识到它是引用,因为局部赋值可以优先,但它显然是引用传递
#7
14
Ruby is pass-by-value in a strict sense, BUT the values are references.
Ruby是严格意义上的按值传递,但值是引用。
This could be called "pass-reference-by-value". This article has the best explanation I have read: http://robertheaton.com/2014/07/22/is-ruby-pass-by-reference-or-pass-by-value/
这可以称为“按值传递引用”。这篇文章有我读过的最好的解释:http://robertheaton.com/2014/07/22/is-ruby-pass-by-reference-or-pass-by-value/
Pass-reference-by-value could briefly be explained as follows:
按值传递参照可以简单地解释如下:
A function receives a reference to (and will access) the same object in memory as used by the caller. However, it does not receive the box that the caller is storing this object in; as in pass-value-by-value, the function provides its own box and creates a new variable for itself.
函数接收对内存中调用者使用的相同对象的引用(并将访问)。但是,它没有接收到调用者正在将该对象存储在的框;就像在传递值中一样,函数提供了自己的框,并为自己创建了一个新的变量。
The resulting behavior is actually a combination of the classical definitions of pass-by-reference and pass-by-value.
结果的行为实际上是引用传递和值传递的经典定义的组合。
#8
8
Parameters are a copy of the original reference. So, you can change values, but cannot change the original reference.
参数是原始引用的副本。因此,您可以更改值,但不能更改原始引用。
#9
1
Ruby is interpreted. Variables are references to data, but not the data itself. This facilitates using the same variable for data of different types.
Ruby是解释。变量是对数据的引用,而不是数据本身。这便于对不同类型的数据使用相同的变量。
Assignment of lhs = rhs then copies the reference on the rhs, not the data. This differs in other languages, such as C, where assignment does a data copy to lhs from rhs.
lhs的赋值等于rhs,然后拷贝rhs上的引用,而不是数据。这在其他语言中是不同的,比如C,在这里,赋值从rhs中复制到lhs。
So for the function call, the variable passed, say x, is indeed copied into a local variable in the function, but x is a reference. There will then be two copies of the reference, both referencing the same data. One will be in the caller, one in the function.
对于函数调用,传递的变量,比如x,确实被复制到函数的局部变量中,但是x是一个引用。然后将有两个引用副本,都引用相同的数据。一个在调用者,一个在函数中。
Assignment in the function would then copy a new reference to the function's version of x. After this the caller's version of x remains unchanged. It is still a reference to the original data.
然后,函数中的赋值将复制一个新的引用到函数的x版本,在此之后,调用者的x版本将保持不变。它仍然是对原始数据的引用。
In contrast, using the .replace method on x will cause ruby to do a data copy. If replace is used before any new assignments then indeed the caller will see the data change in its version also.
相反,在x上使用.replace方法将导致ruby进行数据复制。如果在任何新赋值之前使用了replace,那么调用者也将看到其版本中的数据更改。
Similarly, as long as the original reference is in tact for the passed in variable, the instance variables will be the same that the caller sees. Within the framework of an object, the instance variables always have the most up to date reference values, whether those are provided by the caller or set in the function the class was passed in to.
类似地,只要原始引用对于传入的变量是熟练的,那么实例变量将与调用者看到的相同。在对象的框架中,实例变量总是具有最新的引用值,无论这些值是由调用者提供的,还是在传递给类的函数中设置的。
The 'call by value' or 'call by reference' is muddled here because of confusion over '=' In compiled languages '=' is a data copy. Here in this interpreted language '=' is a reference copy. In the example you have the reference passed in followed by a reference copy though '=' that clobbers the original passed in reference, and then people talking about it as though '=' were a data copy.
这里的“按值调用”或“按引用调用”是混乱的,因为编译语言中的“=”是一个数据副本。这里的解释语言'='是一个参考副本。在这个例子中,引用传递了一个引用副本,尽管“=”这个词是引用的原始版本,然后人们谈论它就好像“=”是一个数据副本。
To be consistent with definitions we must keep with '.replace' as it is a data copy. From the perspective of '.replace' we see that this is indeed pass by reference. Furthermore, if we walk through in the debugger, we see references being passed in, as variables are references.
为了与定义保持一致,我们必须遵守'。替换为数据拷贝。从…的角度。替换“我们看到这确实是通过引用传递的”。此外,如果我们在调试器中遍历,我们会看到正在传入的引用,因为变量是引用。
However if we must keep '=' as a frame of reference, then indeed we do get to see the passed in data up until an assignment, and then we don't get to see it anymore after assignment while the caller's data remains unchanged. At a behavioral level this is pass by value as long as we don't consider the passed in value to be composite - as we won't be able to keep part of it while changing the other part in a single assignment (as that assignment changes the reference and the original goes out of scope). There will also be a wart, in that instance variables in objects will be references, as are all variables. Hence we will be forced to talk about passing 'references by value' and have to use related locutions.
但是,如果我们必须将'='作为一个参考框架,那么我们确实可以在赋值之前看到传入的数据,然后在赋值之后,当调用者的数据保持不变时,我们就不会再看到它了。在行为层面上,这是按值传递,只要我们不认为传入值组合,我们将无法保持它的一部分而改变另一部分在一个任务(任务变化的参考和原始超出范围)。也会有一个疣,在那个实例变量中,对象将是引用,所有的变量都是。因此,我们将*谈论通过“价值参考”,并使用相关的对话。
#10
1
Try this:--
试试这个:——
1.object_id
#=> 3
2.object_id
#=> 5
a = 1
#=> 1
a.object_id
#=> 3
b = 2
#=> 2
b.object_id
#=> 5
identifier a contains object_id 3 for value object 1 and identifier b contains object_id 5 for value object 2.
标识符a包含值对象1的object_id 3,标识符b包含值对象2的object_id 5。
Now do this:--
现在这样做:—
a.object_id = 5
#=> error
a = b
#value(object_id) at b copies itself as value(object_id) at a. value object 2 has object_id 5
#=> 2
a.object_id
#=> 5
Now, a and b both contain same object_id 5 which refers to value object 2. So, Ruby variable contains object_ids to refer to value objects.
现在,a和b都包含相同的object_id 5,它指的是值对象2。因此,Ruby变量包含object_ids来引用值对象。
Doing following also gives error:--
这样做也会产生错误:——
c
#=> error
but doing this won't give error:--
但这样做不会出错:。
5.object_id
#=> 11
c = 5
#=> value object 5 provides return type for variable c and saves 5.object_id i.e. 11 at c
#=> 5
c.object_id
#=> 11
a = c.object_id
#=> object_id of c as a value object changes value at a
#=> 11
11.object_id
#=> 23
a.object_id == 11.object_id
#=> true
a
#=> Value at a
#=> 11
Here identifier a returns value object 11 whose object id is 23 i.e. object_id 23 is at identifier a, Now we see an example by using method.
这里的标识符a返回值对象11,其对象id为23,即object_id 23位于标识符a,现在我们通过使用方法看到一个示例。
def foo(arg)
p arg
p arg.object_id
end
#=> nil
11.object_id
#=> 23
x = 11
#=> 11
x.object_id
#=> 23
foo(x)
#=> 11
#=> 23
arg in foo is assigned with return value of x. It clearly shows that argument is passed by value 11, and value 11 being itself an object has unique object id 23.
在foo中的arg被赋值为x的返回值,它清楚地显示了参数是通过值11传递的,而value 11本身是一个对象,它有唯一的对象id 23。
Now see this also:--
现在看到这也:—
def foo(arg)
p arg
p arg.object_id
arg = 12
p arg
p arg.object_id
end
#=> nil
11.object_id
#=> 23
x = 11
#=> 11
x.object_id
#=> 23
foo(x)
#=> 11
#=> 23
#=> 12
#=> 25
x
#=> 11
x.object_id
#=> 23
Here, identifier arg first contains object_id 23 to refer 11 and after internal assignment with value object 12, it contains object_id 25. But it does not change value referenced by identifier x used in calling method.
在这里,标识符arg首先包含object_id 23以引用11,在使用值对象12进行内部赋值之后,它包含object_id 25。但它不改变在调用方法中使用的标识符x引用的值。
Hence, Ruby is pass by value and Ruby variables do not contain values but do contain reference to value object.
因此,Ruby是按值传递的,而Ruby变量不包含值,而是包含对值对象的引用。
#11
1
It should be noted that you do not have to even use the "replace" method to change the value original value. If you assign one of the hash values for a hash, you are changing the original value.
需要注意的是,您甚至不需要使用“replace”方法来更改原始值。如果您为散列分配了一个散列值,那么您将改变原来的值。
def my_foo(a_hash)
a_hash["test"]="reference"
end;
hash = {"test"=>"value"}
my_foo(hash)
puts "Ruby is pass-by-#{hash["test"]}"
#12
1
Two references refer to same object as long as there is no reassignment.
Any updates in the same object won't make the references to new memory since it still is in same memory. Here are few examples :
同一对象中的任何更新都不会对新内存进行引用,因为它仍然在同一内存中。这里有几个例子:
a = "first string"
b = a
b.upcase!
=> FIRST STRING
a
=> FIRST STRING
b = "second string"
a
=> FIRST STRING
hash = {first_sub_hash: {first_key: "first_value"}}
first_sub_hash = hash[:first_sub_hash]
first_sub_hash[:second_key] = "second_value"
hash
=> {first_sub_hash: {first_key: "first_value", second_key: "second_value"}}
def change(first_sub_hash)
first_sub_hash[:third_key] = "third_value"
end
change(first_sub_hash)
hash
=> {first_sub_hash: {first_key: "first_value", second_key: "second_value", third_key: "third_value"}}