【问题标题】:Are arguments passed to methods by reference or value?参数是通过引用还是值传递给方法?
【发布时间】:2012-02-03 21:14:38
【问题描述】:

当您将参数传递给 Ruby 中的方法时,任何人都可以扩展、更正或验证我的感受吗?这些点有错吗?我错过了什么吗?

  • Ruby 中的一切都是对象。
  • 变量是对对象的引用
  • (将变量传入方法时):方法中捕获变量的参数是该方法的局部变量。参数(局部变量)现在也具有对同一对象的引用。
  • 我可以更改对象(就地),并且当退出方法范围时,此更改将保持不变。在方法范围之外引用此对象的任何变量都将反映该对象已被更改。
  • 对该参数(局部变量)的新赋值不会改变原始对象,因此当方法离开作用域时对其的任何引用都将保持不变。
  • 如果我将一个变量传递给引用一个整数的方法,那么一旦该方法退出,我就无法让该变量引用一个新的整数。

有没有办法让一个方法将一个整数作为其参数之一,做一些事情,也许作为副作用会改变值,一旦方法退出就会反映这种变化。也许我只是不考虑“Ruby 方式”。

【问题讨论】:

标签: ruby pass-by-reference pass-by-value


【解决方案1】:

Ruby 中的一切都是对象。

足够接近。

变量是对对象的引用

没有。一个变量“命名”一个对象:当一个变量被计算时,它计算为它当前“命名”的对象。在内部,这是通过“存储指针”(或等效机制)到对象来完成的。 (虽然实现不需要总是使用指针:例如,在 Ruby MRI 中,Fixnum 值实际上存在 一个真实的对象。)

(将变量传递给方法时):方法中捕获变量的参数是该方法的局部变量。参数(局部变量)现在也引用了同一个对象。

没有。往上看。但是,这两个变量现在命名(或“评估”)同一个对象。 内部使用Call-by-Value传递参数——也就是说,内部传递指向对象的指针——尽管Ruby有Call-by-Object-Sharing语义,这是一个我尝试推广的术语,因为我发现它简洁地描述了行为。

我可以(就地)更改对象,并且当退出方法范围时,此更改将保持不变。在方法范围之外引用此对象的任何变量都将反映该对象已被更改。

是的,一个对象就是它自己。如果你改变那个对象,你就会在任何地方改变那个对象。但请注意:没有任何变量被更改。内部和外部变量都将仍然命名(或“评估”)相同的对象

对该参数(局部变量)的新赋值不会改变原始对象,因此当方法离开作用域时对它的任何引用都将保持不变。

正确。如果您为创建它的局部变量(局部变量)分配不同的值,则命名不同的对象。 Ruby 不是 Call-by-Reference,因此调用上下文中的变量不会改变。

如果我将变量传递给引用 Integer 的方法,那么一旦该方法退出,我就无法让该变量引用新的 Integer?

变量从不传递。 变量被评估为它们命名的对象并传递这些对象。无论如何,我们知道:

  1. Ruby 不是 Call-by-Reference 和;
  2. 整数(Fixnums)是不可变的

因此:

x = 1
y.foo(x)

不能永远更改x 的名称,甚至不能更改对象x 名称的内容(因为它是不可变的)。即使x 命名的对象是可变的,该方法不可能 改变what 对象x 的名称:它只能变异 评估x 产生的对象。

编码愉快。


现在,Ruby 方式——在我的书中——将使用一个更好的返回值来包含 all 新状态,并让调用者将它放在需要去的地方:- )

当然,可变对象(包括简单数组)也是一种选择,但这是ick。而且,如果有足够多的状态可以一起旅行,它可能是一个单独的类的候选者。


作为结束语:Ruby 支持闭包的概念,因此可以以词法范围的方式

x = 1; (lamb­da {|a| x = a}).c­all(2); x  // => 2

(这是为一个简单的 lambda 显示的,但可以设计/制作一个类似的方法:在像这样的所有愚蠢的反例中,outside 变量本身需要是但是,已知,因为 lambda/方法无法将外部变量名称设为新对象。)

【讨论】:

  • 感谢您的精彩回答!至于“名称”与“引用”语义,我不明白其中的区别。一个变量“命名”了一个对象……这给了它一个对该对象的“引用”。是否可以“命名”一个对象而不是“引用”它?是否可以对对象进行“引用”而不是“命名”它?有没有可以指出这种关系图的例子,也许还有另一种语言的例子,其中事情在幕后做的不同?我只是不明白“命名”一个对象和“引用”一个对象是不同的东西。
  • 我觉得这些术语是可以互换的,“命名”一个对象意味着“引用”它,“引用”一个对象意味着你给它一个“名字”。
  • @slindsey3000 我更喜欢术语“名称”——这在 Python 中更为流行——正是因为它使用“引用”或任何变体。 “[Pass by] Reference[es]”是这样一个重载的词集。但是,是的,通俗地说,他们多次受到同样的对待。但是,当仅使用“名称”并仅定义其与变量评估结果的关系时,可以避免在扩展范围以讨论许多其他语言中的值/变量时发生冲突。在 C++ 中说“int x = 1; // x reference 1”是非常错误的。 “命名”的概念更笼统(和边缘)。
  • @slindsey3000 也就是说,就像术语“按对象共享调用”一样,可以在不定义或关心如何完成的情况下定义语义,在许多不同的语言中有许多不同的方式。
  • 然而,这与他们在 Java 中称为 pass-by-value 的完全相同语义相同
猜你喜欢
  • 2020-04-01
  • 2016-12-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-03-15
  • 2014-12-26
  • 1970-01-01
  • 2012-10-11
相关资源
最近更新 更多