【问题标题】:Is there a meaningful difference between pass_by_reference vs pass_by_object_sharing in ruby?ruby 中的 pass_by_reference 与 pass_by_object_sharing 之间是否存在有意义的区别?
【发布时间】:2014-12-21 23:50:53
【问题描述】:

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

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

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

【问题讨论】:

  • 不要引用那么长的文本。提取对立点。
  • @sawa 不是我在乎的,但是为此给出-1 是荒谬的。我想确保我给每个人正确的上下文/以防我错过了什么。如果很多人认为没有必要,我会删除它。

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


【解决方案1】:

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

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

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

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

我不喜欢人们想出诸如“传递对象共享”之类的新名称,因为他们不了解语义已被现有术语传递值所涵盖。添加一个新术语只会增加而不是减少混淆,因为它不会解决现有术语的定义,只会添加一个同样需要定义的新术语。

【讨论】:

    【解决方案2】:

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

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

    如果在 Ruby 中实现了“引用调用”,它会是这样的:

    def f(byref x)
        x = "CHANGED"
    end
    
    x = ""
    f(x)
    
    # X is "CHANGED"
    

    这里,x 的值被改变了。对象 x 所指的值。

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

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

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

    【讨论】:

    • C# 是一个很好的比较,因为它有按值传递值类型、按值传递引用类型、按引用传递值类型和按引用传递引用类型。在按值传递引用类型时,Ruby(以及 Python 和 ECMAScript 以及 Smalltalk 和 Java 以及……)的语义与 C# 的语义匹配 100%。因此,为什么在 C# 中调用按值传递而在 Ruby 中调用其他的东西是完全没有意义的。
    • 我实际上发布了一个 C# 的 sn-p,在我关于 SO 的一个答案中演示了这四种语义。无聊的时候可以去挖掘一下。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-09-12
    • 1970-01-01
    • 2020-03-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-04-02
    相关资源
    最近更新 更多