上下文:我认为说pass_by_reference真的是pass_by_sharing是误导性的 以下是我正在反对的“有效的红宝石”一书的摘录
“大多数对象作为引用而不是实际值传递。当这些类型的对象插入容器时,集合类实际上存储对象的引用而不是对象本身。(显着的例外) rule是Fixnum类,其对象始终按值传递,而不是通过引用传递。)
当对象作为方法参数传递时也是如此。该方法将接收对象的引用,而不是新副本。这对效率很有帮助,但却具有惊人的含义。 “
答案 0 :(得分:3)
'按值调用'和'按对象共享调用'术语与Ruby的行为相匹配,并且 术语与具有相同的其他面向对象的语言一致 语义。
'按值调用'和'按对象共享调用'在面向对象的语言中基本上意味着相同的事情,因此使用哪一个并不重要。有人只是认为它会澄清术语中的混淆,增加更多的术语。
如果在Ruby中实现'通过引用调用',它将类似于:
def f(byref x)
x = "CHANGED"
end
x = ""
f(x)
# X is "CHANGED"
这里,x的值改变了。对象x引用的值。
使用术语“按引用调用”只会产生混淆,因为它们意味着 对不同的人有不同的看法。这是不必要的 像Ruby这样的语言,因为你没有选择。在不同的语言中 调用像C ++和C#这样的机制,因为教这些术语更有意义 它们对程序产生了实际影响,我们可以提出非假设的例子 他们。
在Ruby中解释参数时,您不需要使用任何这些术语。 对于那些还不懂语言的人来说,它们毫无意义。只是 用这个术语描述行为本身并避免行李。
我会说如果你坚持使用这些术语,那就使用'按值调用',因为它通常被认为更正确。 “Programming Ruby”一书将其称为“按值调用”,以及大量的Ruby程序员。使用与其技术含义不同的术语是没有用的。
答案 1 :(得分:1)
你是对的。 Ruby只是按值传递。 Ruby中传递和赋值的语义与Java中的语义完全相同。并且Java被普遍描述(在Stack Overflow和Internet的其余部分上)仅作为传值。关于语言的术语,例如传值和传递引用,必须在各种语言中一致使用才有意义。
那些经常被Java,Ruby等人误解的东西"通过引用传递对象"就是"对象"不是这些语言中的值,因此不能通过"。每个变量的值和每个表达式的结果都是"引用",它是指向对象的指针。用于创建对象的表达式返回对象指针;当您通过点表示法访问属性时,左侧采用对象指针;当您将一个变量分配给另一个变量时,您将复制指针,从而产生指向同一对象的两个指针。你总是处理指向对象的指针,从不对象本身。
这在Java中是明确的,因为Java中唯一的类型是原始类型和引用类型 - 没有"对象类型"。因此,Java中不是基元的每个值都是引用(指向对象的指针)。 Ruby是动态类型的,因此变量不具有显式类型。但是你可以把动态类型语言想象成只有一种类型的静态类型语言;对于像Python和Ruby这样的语言,如果描述了这种类型,它就是指向对象的类型。
问题最终归结为定义问题。人们争论事物是因为没有确切的定义,或者每个人的定义都略有不同。而不是争论模糊定义的东西,比如什么是"价值"一个变量,或者命名值是否是"变量"或者"名称"等,我们需要使用传值和传递引用的定义,它完全基于语言结构的语义。 @ fgb的答案提供了一个明确的语义测试,用于传递引用。在"真正的传递参考",例如在C ++和PHP中使用&
,或在C#中使用ref
或out
,对参数变量的简单赋值(即=
)与对简单赋值的简单赋值具有相同的效果在原始范围内传递变量。在按值传递时,对参数变量的简单赋值(即=
)在原始范围中无效。这就是我们在Java,Python,Ruby和许多其他语言中看到的。
我不喜欢人们想出像#34;通过对象共享"这样的新名字,当他们不了解语义是由现有术语,传值进行覆盖时。添加新术语只会增加混淆而不是减少它,因为它不能解析现有术语的定义,只会添加一个也需要定义的新术语。