参数是通过引用还是值传递给方法的?

时间:2012-01-06 02:50:28

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

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

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

有没有办法让一个方法将其参数作为其中一个参数作为整数,做一些事情,并且可能作为副作用更改值,一旦方法退出就反映出该变化。也许我只是不想“红宝石的方式”。

1 个答案:

答案 0 :(得分:20)

  

Ruby中的所有东西都是一个对象。

足够近。

  

变量是对象的引用

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

  

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

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

  

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

是的,一个物体本身。如果你改变那个对象,你就会在任何地方改变那个对象。但请注意:没有任何变量被更改。内部和外部变量名称(或“评估为”)同一对象

  

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

正确。如果为您创建的局部变量分配不同的值,则局部变量将其命名为另一个对象。 Ruby Call-by-Reference所以调用上下文中的变量不会改变。

  

如果我将一个变量传递给引用Integer的方法,那么一旦该方法退出,我实际上没有办法让该变量引用一个新的Integer?

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

  1. Ruby Call-by-Reference and;
  2. 整数(Fixnums)是不可变的
  3. 因此:

    x = 1
    y.foo(x)
    

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

    快乐的编码。


    现在,Ruby Way - 在我的书中 - 将使用一个更好的返回值,包含所有新状态,并让调用者将它放在需要的位置: - )

    当然,可变对象(包括简单数组)也是一种选择,但那是 ick 。而且,如果有足够的州一起旅行,它可能是一个单独的班级的候选人。


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

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

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