红宝石中的pass_by_reference与pass_by_object_sharing之间有什么有意义的区别吗?

Is there a meaningful difference between pass_by_reference vs pass_by_object_sharing in ruby?

提问人:Lewix 提问时间:10/27/2014 最后编辑:Lewix 更新时间:10/28/2014 访问量:166

问:

上下文:我认为,当它真正pass_by_sharing时说pass_by_reference是误导
性的 这是我反对的“Effective Ruby”一书的摘录

“大多数对象都是作为参考而不是实际值传递的。当这些类型的对象插入到容器中时,集合类实际上存储的是对象的引用,而不是对象本身。(该规则值得注意的例外是 Fixnum 类,其对象始终按值传递,而不是按引用传递。

当对象作为方法参数传递时也是如此。该方法将接收对对象的引用,而不是新副本。这对效率有好处,但有一个惊人的影响。 "

Ruby 按引用传递

评论

0赞 sawa 10/27/2014
不要引用那么长的文本。提取对立点。
0赞 Lewix 10/27/2014
@sawa我不在乎,但为此给 -1 是荒谬的。我想确保我给每个人适当的背景/以防万一我错过了什么。如果许多人认为没有必要,我会删除它。

答:

3赞 fgb 10/27/2014 #1

“按值调用”和“按对象共享调用”的术语与 Ruby 的行为相匹配,并且 该术语与其他具有相同 语义学。

在面向对象的语言中,“按值调用”和“按对象共享调用”的意思基本相同,因此使用哪一个并不重要。有人只是认为添加更多术语可以澄清术语中的混淆。

但是,如果“通过引用调用”是在 Ruby 中实现的,它将是这样的:

def f(byref x)
    x = "CHANGED"
end

x = ""
f(x)

# X is "CHANGED"

在这里,x 的值发生了变化。对象 x 所指的值。

不过,使用术语“按引用调用”只会造成混淆,因为它们的意思是 不同的东西给不同的人。这是不必要的 像 Ruby 这样的语言,因为你别无选择。在不同语言中 调用像 C++ 和 C# 这样的机制,教授这些术语更有意义,因为 它们对程序有真正的影响,我们可以提出非假设的例子 他们。

在 Ruby 中解释参数时,您不需要使用任何这些术语。 对于还不懂语言的人来说,它们毫无意义。只 在没有该术语的情况下描述行为本身并避免包袱。

我想说的是,如果你坚持使用这些术语,那么就使用“按值调用”,因为它通常被认为更正确。《Ruby 编程》一书称其为“按值调用”,许多 Ruby 程序员也称其为“按值调用”。使用具有与其技术含义不同的术语是没有帮助的。

评论

2赞 Jörg W Mittag 10/27/2014
C# 是一个非常好的比较,因为它具有按值传递值类型、按值传递引用类型、按引用传递值类型以及按引用传递引用类型。Ruby(以及 Python 和 ECMAScript、Smalltalk、Java 和 ...)的语义在按值传递引用类型时与 C# 的语义 100% 匹配。因此,为什么完全相同的语义应该在 C# 中称为 pass-by-value,而在 Ruby 中称为其他语义,这根本没有意义。
1赞 Jörg W Mittag 10/27/2014
实际上,我在 SO 上的一个答案中发布了一段 C# 片段,演示了这四个语义。如果你觉得无聊,你可以把它挖出来。
1赞 newacct 10/28/2014 #2

你是对的。Ruby 仅按值传递。Ruby 中传递和赋值的语义与 Java 中的语义完全相同。而 Java 被普遍描述为(在 Stack Overflow 和 Internet 的其余部分)仅按值传递。有关语言的术语(如按值传递和按引用传递)必须跨语言一致地使用才有意义。

那些说 Java、Ruby 等“通过引用传递对象”的人经常误解的一点是,“对象”在这些语言中不是值,因此不能“传递”。每个变量的值和每个表达式的结果都是一个“引用”,它是指向对象的指针。用于创建对象的表达式返回对象指针;当您通过点表示法访问属性时,左侧采用对象指针;将一个变量分配给另一个变量时,会复制指针,从而生成指向同一对象的两个指针。你总是处理指向对象的指针,而不是对象本身。

这在 Java 中是明确的,因为 Java 中唯一的类型是原始类型和引用类型——没有“对象类型”。因此,Java 中每个不是原语的值都是一个引用(指向对象的指针)。Ruby 是动态类型的,因此变量没有显式类型。但是你可以把动态类型语言想象成一种静态类型语言,只有一种类型;对于像 Python 和 Ruby 这样的语言,如果描述了这种类型,它就是指向对象的指针类型。

这个问题最终归结为定义问题。人们争论不休,因为没有精确的定义,或者他们每个人的定义略有不同。与其争论定义模糊的东西,比如什么是变量的“值”,或者命名值是“变量”还是“名称”等,我们需要使用一个纯粹基于语言结构语义的按值传递和按引用传递的定义。@fgb的回答为通过引用提供了一个清晰的语义测试。在“真正的通过引用传递”中,例如在 C++ 和 PHP 中,或者在 C# 中使用或,对参数变量的简单赋值(即 )与在原始作用域中对传递的变量的简单赋值具有相同的效果。在按值传递中,对参数变量的简单赋值(即 )在原始作用域中不起作用。这就是我们在 Java、Python、Ruby 和许多其他语言中看到的。&refout==

我不喜欢人们想出像“传递对象共享”这样的新名称,当他们不理解语义被现有术语传递值所覆盖时。添加一个新术语只会增加而不是减少混淆,因为它不能解决现有术语的定义,只是添加一个也需要定义的新术语。