Ruby 是按引用传递还是按值传递?

发布于 2024-08-14 05:37:25 字数 827 浏览 9 评论 0原文

@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 对象将错误添加到 update_lanugages 方法中的 lang_errors 变量。 当我对 @user 对象执行保存时,我丢失了最初存储在 lang_errors 变量中的错误。

虽然我试图做的更多的是黑客(这似乎不起作用)。我想了解为什么变量值被冲掉。我理解按引用传递,所以我想知道如何将值保存在该变量中而不被清除。

@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.

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(14

懵少女 2024-08-21 05:37:26

Ruby 被解释。变量是对数据的引用,但不是数据本身。这有助于对不同类型的数据使用相同的变量。

赋值 lhs = rhs 然后复制 rhs 上的引用,而不是数据。这在其他语言中有所不同,例如 C,其中赋值会将数据从 rhs 复制到 lhs。

因此,对于函数调用,传递的变量(例如 x)确实被复制到函数中的局部变量中,但 x 是一个引用。然后将有两个引用副本,两者都引用相同的数据。一个在调用者中,一个在函数中。

然后,函数中的赋值会将新引用复制到该函数的 x 版本。此后,调用者的 x 版本保持不变。仍然是对原始数据的引用。

相反,在 x 上使用 .replace 方法将导致 ruby​​ 执行数据复制。如果在任何新分配之前使用替换,那么调用者实际上也会看到其版本中的数据更改。

类似地,只要传入变量的原始引用完好无损,实例变量将与调用者看到的相同。在对象的框架内,实例变量始终具有最新的引用值,无论这些引用值是由调用者提供还是在类传递到的函数中设置。

由于对“=”的混淆,“按值调用”或“按引用调用”在这里被混淆了。在编译语言中,“=”是数据副本。在这种解释性语言中,“=”是参考副本。在该示例中,您传递了引用,然后是引用副本,尽管“=”破坏了原始传入的引用,然后人们谈论它,就好像“=”是数据副本一样。

为了与定义保持一致,我们必须保留“.replace”,因为它是数据副本。从'.replace'的角度我们看到这确实是引用传递。此外,如果我们在调试器中浏览,我们会看到传入的引用,因为变量是引用。

但是,如果我们必须保留“=”作为参考框架,那么实际上我们确实可以看到传入的数据,直到赋值为止,然后在赋值之后我们就看不到它了,而调用者的数据保持不变。在行为层面上,只要我们不认为传入的值是复合的,这就是按值传递 - 因为我们无法在单个赋值中更改其他部分时保留其中的一部分(因为该赋值更改参考文献并且原始文献超出范围)。还有一个缺点,就是对象中的实例变量将被引用,就像所有变量一样。因此,我们将被迫谈论传递“按值引用”,并且必须使用相关的措辞。

Ruby is interpreted. Variables are references to data, but not the data itself. This facilitates using the same variable for data of different types.

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.

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.

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.

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.

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.

反目相谮 2024-08-21 05:37:26

是的,但是....

Ruby 传递对对象的引用,并且由于Ruby 中的所有内容都是对象,因此您可以说它是按引用传递。

我不同意这里的帖子声称它是按值传递的,这对我来说似乎是迂腐的、象征性的游戏。

然而,实际上它“隐藏”了行为,因为 ruby​​ 提供了“开箱即用”的大多数操作 - 例如字符串操作,生成对象的副本:

> astringobject = "lowercase"

> bstringobject = astringobject.upcase
> # bstringobject is a new object created by String.upcase

> puts astringobject
lowercase

> puts bstringobject
LOWERCASE

这意味着大多数时候,原始对象保持不变看起来 ruby​​ 是“按值传递”。

当然,在设计自己的类时,了解此行为的细节对于功能行为、内存效率和性能都很重要。

Yes but ....

Ruby passes a reference to an object and since everything in ruby is an object, then you could say it's pass by reference.

I don't agree with the postings here claiming it's pass by value, that seems like pedantic, symantic games to me.

However, in effect it "hides" the behaviour because most of the operations ruby provides "out of the box" - for example string operations, produce a copy of the object:

> astringobject = "lowercase"

> bstringobject = astringobject.upcase
> # bstringobject is a new object created by String.upcase

> puts astringobject
lowercase

> puts bstringobject
LOWERCASE

This means that much of the time, the original object is left unchanged giving the appearance that ruby is "pass by value".

Of course when designing your own classes, an understanding of the details of this behaviour is important for both functional behaviour, memory efficiency and performance.

蓝礼 2024-08-21 05:37:25

其他回答者都是正确的,但是一个朋友让我向他解释一下,这实际上归结为 Ruby 如何处理变量,所以我想我会分享一些我为他写的简单图片/解释(对篇幅表示歉意)可能有些过于简单化):


Q1:当您将新变量 str 分配给 'foo' 值时会发生什么?

str = 'foo'
str.object_id # => 2000

在此处输入图像描述

A:创建一个名为 str 的标签,指向对象 'foo',对于这个 Ruby 解释器的状态来说,它恰好位于内存位置 2000


Q2:当使用 = 将现有变量 str 分配给新对象时会发生什么?

str = 'bar'.tap{|b| puts "bar: #{b.object_id}"} # bar: 2002
str.object_id # => 2002

在此处输入图像描述

答:标签 str 现在指向不同的对象。


Q3:将新变量 = 赋给 str 时会发生什么?

str2 = str
str2.object_id # => 2002

在此处输入图像描述

答:创建一个名为 str2 的新标签,指向 str相同的对象。


Q4:如果 strstr2 引用的对象发生变化,会发生什么?

str2.replace 'baz'
str2 # => 'baz'
str  # => 'baz'
str.object_id # => 2002
str2.object_id # => 2002

在此处输入图像描述

A:两个标签仍然指向同一个对象,但该对象本身已发生突变(其内容已更改)成为别的东西)。


这与原来的问题有什么关系?

与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

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):


Q1: What happens when you assign a new variable str to a value of 'foo'?

str = 'foo'
str.object_id # => 2000

enter image description here

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

enter image description here

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

enter image description here

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

enter image description here

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:

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
滴情不沾 2024-08-21 05:37:25

在传统术语中,Ruby 是严格按值传递的。然而,Ruby 中的一切都是对象,因此 Ruby 的行为看起来就像按引用传递语言。

Ruby 打破了“按引用传递”或“按值传递”的传统定义,因为一切都是对象,并且当它传递事物时,它会传递对对象的引用。事实上,Ruby 可以被归类为第三种语言,我们可以称之为“通过对象引用传递”。按照计算机科学术语的严格定义,Ruby 是按值传递的。

Ruby 没有任何纯非引用值的概念,因此您不能将值传递给方法。变量始终是对象的引用。为了获得一个不会从你下面改变的对象,你需要复制或克隆你传递的对象,从而给出一个其他人没有引用的对象。然而,即使这样也不是万无一失的:两种标准克隆方法都会进行浅复制,因此克隆的实例变量仍然指向与原始对象相同的对象。如果 ivars 引用的对象发生变化,它仍然会显示在副本中,因为它引用相同的对象。

In traditional terminology, Ruby is strictly pass-by-value. However, everything in Ruby is an object, so Ruby can appear to behave like pass-by-reference languages.

Ruby breaks the traditional definition of "pass-by-reference" or "pass-by-value" because everything is an object, and when it passes things, it passes references to objects. So really, it Ruby can be classified as a 3rd type of language we might call "pass by object reference." In the strict definition of the computer science term, Ruby is pass-by-value.

Ruby doesn't have any concept of a pure, non-reference value, so you 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. However, even this isn't bulletproof: 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.

红衣飘飘貌似仙 2024-08-21 05:37:25

Ruby 使用“按对象引用传递”

(使用 Python 的术语)。

说 Ruby 使用“按值传递”或“按引用传递”实际上描述性不够,没有什么帮助。我认为现在大多数人都知道,这个术语(“值”与“引用”)来自 C++。

在 C++ 中,“按值传递”意味着函数获取变量的副本,并且对副本的任何更改都不会更改原始变量。对于物体来说也是如此。如果按值传递对象变量,则整个对象(包括其所有成员)都会被复制,并且对成员的任何更改都不会更改原始对象上的这些成员。 (据我所知,如果按值传递指针,情况会有所不同,但 Ruby 没有指针。)

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;
}

输出:

in inc: 6
in main: 5
in inc: 1
in main: 1

在 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;
}

输出:

in replace: 10
in main: 10

如果参数不是对象,则 Ruby 使用按值传递(在 C++ 意义上)。但在 Ruby 中一切都是对象,因此 Ruby 中实际上不存在 C++ 意义上的值传递。

在 Ruby 中,使用“通过对象引用传递”(使用 Python 的术语):

  • 在函数内部,任何对象的成员都可以分配新值,并且这些更改将在函数返回后持续存在。*
  • 在函数内部,分配变量的全新对象会导致变量停止引用旧对象。但函数返回后,原来的变量仍然会引用旧对象。

因此,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

输出:

1
2
2
3
2

1
2
1

* 这就是为什么在 Ruby 中,如果您想要修改函数内的对象,但在函数返回时忘记了这些更改,那么您必须在对副本进行临时更改之前显式创建该对象的副本。

Ruby uses "pass by object reference"

(Using Python's terminology.)

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++.

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.)

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.

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.

In Ruby, "pass by object reference" (to use Python's terminology) is used:

  • 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.

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.

美煞众生 2024-08-21 05:37:25

Ruby 是按引用传递还是按值传递?

Ruby 是按值传递的。总是。没有例外。没有如果。没有但是。

这是一个简单的程序,它证明了这一事实:

def foo(bar)
  bar = 'reference'
end

baz = 'value'

foo(baz)

puts "Ruby is pass-by-#{baz}"
# Ruby is pass-by-value

Is Ruby pass by reference or by value?

Ruby is pass-by-value. Always. No exceptions. No ifs. No buts.

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
故乡的云 2024-08-21 05:37:25

Ruby 严格意义上是按值传递,但值是引用。

这可以称为“按值传递引用”。这篇文章有我读过的最好的解释:http ://robertheaton.com/2014/07/22/is-ruby-pass-by-reference-or-pass-by-value/

Pass-reference-by-value可以简单解释如下:

函数接收对调用者使用的内存中同一对象的引用(并将访问)。但是,它不会接收调用者存储该对象的框;与按值传递一样,该函数提供自己的框并为自己创建一个新变量。

由此产生的行为实际上是按引用传递和按值传递的经典定义的组合。

Ruby is pass-by-value in a strict sense, BUT the values are references.

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/

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.

缪败 2024-08-21 05:37:25

已经有一些很好的答案,但我想发布关于这个主题的一对权威的定义,但也希望有人能解释一下权威 Matz(Ruby 的创建者)和 David Flanagan 在他们优秀的 O'Reilly 书中的意思, Ruby 编程语言

[来自 3.8.1:对象引用]

当您将对象传递给 Ruby 中的方法时,传递给该方法的是一个对象引用。它不是对象本身,也不是对该对象的引用的引用。另一种说法是,方法参数是按值传递的,而不是按引用传递的,但传递的值是对象引用。

因为对象引用被传递给方法,所以方法可以使用这些引用来修改底层对象。当方法返回时,这些修改是可见的。

直到最后一段,尤其是最后一句话,这一切对我来说都是有意义的。这充其量是一种误导,更糟糕的是令人困惑。以任何方式,对按值传递引用的修改如何改变底层对象?

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.

[from 3.8.1: Object References]

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.

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?

浅暮の光 2024-08-21 05:37:25

Ruby 是按引用传递还是按值传递?

Ruby 是按引用传递的。总是。没有例外。没有如果。没有但是。

这是一个简单的程序,它证明了这一事实:

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 是按引用传递的 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}"

=>有些人没有意识到它是引用,因为本地赋值可以优先,但它显然是按引用传递的

Is Ruby pass by reference or by value?

Ruby is pass-by-reference. Always. No exceptions. No ifs. No buts.

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 ;)

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

无法回应 2024-08-21 05:37:25

参数是原始参考的副本。因此,您可以更改值,但无法更改原始参考。

Parameters are a copy of the original reference. So, you can change values, but cannot change the original reference.

情丝乱 2024-08-21 05:37:25

试试这个:--

1.object_id
#=> 3

2.object_id
#=> 5

a = 1
#=> 1
a.object_id
#=> 3

b = 2
#=> 2
b.object_id
#=> 5

标识符 a 包含值对象 1 的 object_id 3,标识符 b 包含值对象 2 的 object_id 5。

现在这样做:--

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

现在,a 和 b 都包含相同的 object_id 5,它引用值对象 2。
因此,Ruby 变量包含 object_ids 来引用值对象。

执行以下操作也会出现错误:--

c
#=> 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

这里标识符 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

foo 中的 arg 被赋予返回值 x。
它清楚地表明参数是通过值 11 传递的,而值 11 本身就是一个对象,具有唯一的对象 id 23。

现在还可以看到这一点:--

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

此处,标识符 arg 首先包含 object_id 23 来引用 11,然后使用值对象 12 进行内部赋值,它包含 object_id 25。但它不会更改调用方法中使用的标识符 x 引用的值。

因此,Ruby 是按值传递的,Ruby 变量不包含值,但包含对值对象的引用。

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.

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.

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.

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.

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.

Hence, Ruby is pass by value and Ruby variables do not contain values but do contain reference to value object.

晨敛清荷 2024-08-21 05:37:25

应该注意的是,您甚至不必使用“替换”方法来更改值的原始值。如果您为哈希分配其中一个哈希值,则您将更改原始值。

def my_foo(a_hash)
  a_hash["test"]="reference"
end;

hash = {"test"=>"value"}
my_foo(hash)
puts "Ruby is pass-by-#{hash["test"]}"

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.

def my_foo(a_hash)
  a_hash["test"]="reference"
end;

hash = {"test"=>"value"}
my_foo(hash)
puts "Ruby is pass-by-#{hash["test"]}"
稀香 2024-08-21 05:37:25
Two references refer to same object as long as there is no reassignment. 

同一对象中的任何更新都不会引用新内存,因为它仍然位于同一内存中。
以下是一些例子:

    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"}}
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"}}
郁金香雨 2024-08-21 05:37:25

许多精彩的答案都深入探讨了 Ruby 的“按值传递引用” 的工作原理。但通过实例我可以更好地学习和理解一切。希望这会有所帮助。

def foo(bar)
  puts "bar (#{bar}) entering foo with object_id #{bar.object_id}"
  bar =  "reference"
  puts "bar (#{bar}) leaving foo with object_id #{bar.object_id}"
end

bar = "value"
puts "bar (#{bar}) before foo with object_id #{bar.object_id}"
foo(bar)
puts "bar (#{bar}) after foo with object_id #{bar.object_id}"

# Output
bar (value) before foo with object_id 60
bar (value) entering foo with object_id 60
bar (reference) leaving foo with object_id 80 # <-----
bar (value) after foo with object_id 60 # <-----

正如您所看到的,当我们进入该方法时,我们的栏仍然指向字符串“value”。但随后我们将一个字符串对象“reference”分配给bar,它有一个新的object_id。在这种情况下,foo 内部的 bar 具有不同的范围,并且我们在方法内部传递的任何内容都不再被 bar 访问,因为我们重新分配它并将其指向内存中保存字符串“引用”的新位置。

现在考虑同样的方法。唯一的区别是方法内部的 do

def foo(bar)
  puts "bar (#{bar}) entering foo with object_id #{bar.object_id}"
  bar.replace "reference"
  puts "bar (#{bar}) leaving foo with object_id #{bar.object_id}"
end

bar = "value"
puts "bar (#{bar}) before foo with object_id #{bar.object_id}"
foo(bar)
puts "bar (#{bar}) after foo with object_id #{bar.object_id}"

# Output
bar (value) before foo with object_id 60
bar (value) entering foo with object_id 60
bar (reference) leaving foo with object_id 60 # <-----
bar (reference) after foo with object_id 60 # <-----

注意到区别了吗?我们在这里所做的是:我们修改了该变量所指向的 String 对象的内容。方法内部 bar 的范围仍然不同。

因此,要小心如何对待传递到方法中的变量。如果您就地修改传入的变量(gsub!、replace 等),请在方法名称中用感叹号 ! 进行指示,例如“def foo!”

PS:

重要的是要记住,foo 内部和外部的“bar”是“不同的”“bar”。它们的范围不同。在该方法内部,您可以将“bar”重命名为“club”,结果是相同的。

我经常看到变量在方法内部和外部重复使用,虽然这很好,但它降低了代码的可读性,并且是一种代码味道(恕我直言)。我强烈建议不要做我在上面的例子中所做的事情:)而是这样做

def foo(fiz)
  puts "fiz (#{fiz}) entering foo with object_id #{fiz.object_id}"
  fiz =  "reference"
  puts "fiz (#{fiz}) leaving foo with object_id #{fiz.object_id}"
end

bar = "value"
puts "bar (#{bar}) before foo with object_id #{bar.object_id}"
foo(bar)
puts "bar (#{bar}) after foo with object_id #{bar.object_id}"

# Output
bar (value) before foo with object_id 60
fiz (value) entering foo with object_id 60
fiz (reference) leaving foo with object_id 80
bar (value) after foo with object_id 60

Lots of great answers diving into the theory of how Ruby's "pass-reference-by-value" works. But I learn and understand everything much better by example. Hopefully, this will be helpful.

def foo(bar)
  puts "bar (#{bar}) entering foo with object_id #{bar.object_id}"
  bar =  "reference"
  puts "bar (#{bar}) leaving foo with object_id #{bar.object_id}"
end

bar = "value"
puts "bar (#{bar}) before foo with object_id #{bar.object_id}"
foo(bar)
puts "bar (#{bar}) after foo with object_id #{bar.object_id}"

# Output
bar (value) before foo with object_id 60
bar (value) entering foo with object_id 60
bar (reference) leaving foo with object_id 80 # <-----
bar (value) after foo with object_id 60 # <-----

As you can see when we entered the method, our bar was still pointing to the string "value". But then we assigned a string object "reference" to bar, which has a new object_id. In this case bar inside of foo, has a different scope, and whatever we passed inside the method, is no longer accessed by bar as we re-assigned it and point it to a new place in memory that holds String "reference".

Now consider this same method. The only difference is what with do inside the method

def foo(bar)
  puts "bar (#{bar}) entering foo with object_id #{bar.object_id}"
  bar.replace "reference"
  puts "bar (#{bar}) leaving foo with object_id #{bar.object_id}"
end

bar = "value"
puts "bar (#{bar}) before foo with object_id #{bar.object_id}"
foo(bar)
puts "bar (#{bar}) after foo with object_id #{bar.object_id}"

# Output
bar (value) before foo with object_id 60
bar (value) entering foo with object_id 60
bar (reference) leaving foo with object_id 60 # <-----
bar (reference) after foo with object_id 60 # <-----

Notice the difference? What we did here was: we modified the contents of the String object, that variable was pointing to. The scope of bar is still different inside of the method.

So be careful how you treat the variable passed into methods. And if you modify passed-in variables-in-place (gsub!, replace, etc), then indicate so in the name of the method with a bang !, like so "def foo!"

P.S.:

It's important to keep in mind that the "bar"s inside and outside of foo, are "different" "bar". Their scope is different. Inside the method, you could rename "bar" to "club" and the result would be the same.

I often see variables re-used inside and outside of methods, and while it's fine, it takes away from the readability of the code and is a code smell IMHO. I highly recommend not to do what I did in my example above :) and rather do this

def foo(fiz)
  puts "fiz (#{fiz}) entering foo with object_id #{fiz.object_id}"
  fiz =  "reference"
  puts "fiz (#{fiz}) leaving foo with object_id #{fiz.object_id}"
end

bar = "value"
puts "bar (#{bar}) before foo with object_id #{bar.object_id}"
foo(bar)
puts "bar (#{bar}) after foo with object_id #{bar.object_id}"

# Output
bar (value) before foo with object_id 60
fiz (value) entering foo with object_id 60
fiz (reference) leaving foo with object_id 80
bar (value) after foo with object_id 60
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文