Ruby'通过价值'澄清

时间:2013-11-10 11:38:23

标签: ruby

好的,所以Ruby是'按值传递'。但是,如何在Ruby中准确定义“按引用传递”和“按值传递”?我已经使用了这个答案What's the difference between passing by reference vs. passing by value?并根据它,Ruby似乎是一个混合...

从技术上讲,Ruby似乎是“按值传递”,区别在于当您将值传递给方法时该值不会获得COPIED。如果我们定义“value”=对象,并且“reference”=指向该对象的引用变量,那么“通过引用传递”是否有意义,如果它等同于“传递指向特定对象的引用变量”?然后,一旦传递了“引用”,该方法就不会生成对象的COPY,而实际上具有可以直接操作的ORIGINAL对象本身(由变量引用)。如果我错了,请纠正我。

编辑:我知道这个问题Is Ruby pass by reference or by value?,但是不同的人似乎对通过引用/值的传递有不同的定义。

3 个答案:

答案 0 :(得分:5)

Ruby是值得传递的,就像C,Java,Python,Smalltalk,ECMAScript等等。默认情况下,C ++和C#也是值传递,你必须使用特殊注释(C ++中的&,C#中的ref)来使用传递引用。

区别实际上相当简单:如果传递了引用,则被调用者可以修改它,否则不能。在Ruby中,被调用者不能修改引用,因为它是传值的:

def is_ruby_pass_by_value?(foo)
  foo = 'No, Ruby is pass-by-reference.'
  return nil
end

bar = 'Yes, of course, Ruby *is* pass-by-value!'

is_ruby_pass_by_value?(bar)

p bar
# 'Yes, of course, Ruby *is* pass-by-value!'

正如您所看到的,在方法is_ruby_pass_by_value?中,引用bar / foo 正在传递,否则之后可以看到修改。 {-1}}正按值传递,即bar内容(其中包含的)正在传递, not 引用本身。

现在, 正在传递的值是什么? 不是 bar对象。而是它是{em>指针到该String对象。更准确地说:该指针的副本

现在,有两个指向该String对象的指针。并且String对象是可变的!所以,如果我按照一个指针(String)并告诉foo对象改变自己,然后我按照另一个指针(String)并询问它的内容,然后我显然会看到已更改的内容。这只是共享可变状态的本质,Ruby不是纯粹功能性的,引用透明的语言:

bar

事实上,在Ruby中,变量保存并作为参数传递的值是总是指针。这就是几乎所有面向对象语言的工作方式。 Barbara Liskov将这种特殊情况称为“按对象分享呼叫”,它有时也称为“按共享呼叫”或“逐个呼叫”。

但请注意,传递的值是指针,完全无关紧要。按值传递与按引用传递是关于如何传递参数,而不是参数是什么。无论您是传递def is_ruby_pass_by_value?(foo) foo.replace('More precisely, it is call-by-object-sharing!') foo = 'No, Ruby is pass-by-reference.' return nil end bar = 'Yes, of course, Ruby *is* pass-by-value!' is_ruby_pass_by_value?(bar) p bar # 'More precisely, it is call-by-object-sharing!' 还是指针,C始终都是按值传递。指针仍然按价值传递。同样在Ruby中,指针正在按值传递。 Ruby和C之间的区别是a)你只能 在Ruby中传递指针,b)没有特殊的语法表明你正在传递一个指针。

[注意:大多数Ruby实现实际上都会进行优化,以便直接传递小于指针的对象,而不是将指针传递给该对象。但是,它们只针对语言规范保证的对象具有深层不可变性,因此无法观察将指针传递给值并直接传递值之间的区别。例如,对intFixnumSymbolFloatniltrue进行了此操作。]

以下是C#中的一个示例,它演示了pass-by-value(即使该值是引用)和pass-by-reference之间的区别:

false

答案 1 :(得分:2)

你可以对此进行纯粹主义,并说ruby是“通过参考值传递”的一个特例,但它忽略了这一点。想想红宝石中的所有东西都是对象

foo(14)传递对值为14的整数对象的引用。有些东西在封面下发生,所以你不会得到100个14个对象,但是从意图的角度来看大部分时间你都可以忘记这个概念。

答案 2 :(得分:2)

Ruby是“通过引用传递”。区别如下:如果您通过引用传递,则可以对原始对象执行错误操作:

x = [ "virgin" ]

def do_bad_things_to( arg )
  arg.clear << "bad things"
end

do_bad_things_to( x )

如果您通过值传递,您将获得原始对象的值并可以使用它,但您不能对原始对象执行错误操作。您消耗更多内存,因为原始对象值的副本也需要内存:

def pass_by_value( arg )
  arg.dup
end

y = [ "virgin" ]

do_bad_things_to( pass_by_value( y ) )

p x #=> [ "bad things" ]
p y #=> [ "virgin" ]

对于不可变对象(数字,符号,truefalsenil ...),人们不能凭借其不变性来做坏事。据说,在Ruby中,它们是通过值传递的,但实际上,这种区别对它们来说没什么意义,就像在内存中保留许多内部副本一样没有意义。

更新:关于“参考”的含义似乎存在术语争用。在Ruby中,JörgMittag的“通过引用传递”是通过关闭局部变量的闭包明确实现的:

baz = "Jörg"
define_method :pass_by_Jorgs_reference_to_baz do baz = "Boris" end
pass_by_Jorgs_reference_to_baz
baz #=> "Boris"