好的,所以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?,但是不同的人似乎对通过引用/值的传递有不同的定义。答案 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实现实际上都会进行优化,以便直接传递小于指针的对象,而不是将指针传递给该对象。但是,它们只针对语言规范保证的对象具有深层不可变性,因此无法观察将指针传递给值并直接传递值之间的区别。例如,对int
,Fixnum
,Symbol
,Float
,nil
和true
进行了此操作。]
以下是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" ]
对于不可变对象(数字,符号,true
,false
,nil
...),人们不能凭借其不变性来做坏事。据说,在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"