Ruby 如何在语义上处理赋值?

Posted

技术标签:

【中文标题】Ruby 如何在语义上处理赋值?【英文标题】:How does Ruby handle assignment semantically? 【发布时间】:2015-06-27 16:32:11 【问题描述】:

在 Ruby 中,我们使用 = 运算符为对象赋值。

将此与隐式类型结合起来,我们经常会遇到这样的情况:

myVar= :asymbol

以上行都创建了一个新的符号对象,并将该对象绑定到变​​量名myVar

从语义上讲,这是怎么做到的?

我已经意识到= 运算符是不是解释器内置的魔术语法,但实际上只是object.=(value) 方法的语法糖。

考虑到这一点,我最好的猜测是,当解释器看到我们试图为未定义的变量名赋值时,它首先会创建一个特殊类型的新对象,例如 undefinednull 或一些东西,然后将:= 消息传递给该对象,其中有效负载是我们尝试分配的值。

但是,在未实例化的对象上调用 .class 只会引发异常,因为 Ruby 认为我们正在尝试调用一个方法(其名称是您要创建的变量的名称) self

> obj.class
    > NameError: undefined variable or method 'obj' for main:Object

所以,据我所知,我无法通过实验解决这个问题。


旁注:

在符号赋值的情况下,我相信赋值的值(又名实例化对象的object_id方法返回的值,又名unsigned long VALUE在C级别上的变量的值)是一个代表一个数字在某处的表格中偏移(我相信这就是 Ruby 为符号对象实现“即时价值”的方式)。

在其他情况下,该值可能是对象本身的直接编码,或者是要转换为引用 struct 的指针的值。

无论如何,Ruby 表示对象的方式以及我们最终是分配引用还是对象本身都不是我在这里要问的。

补充问题:

= 方法继承自哪个类?我在 Object 或 BasicObject 的规范中找不到它。

【问题讨论】:

像“没有勺子”,没有=方法。 这是这个问题的副本吗? ***.com/questions/8345755/object-assignment-in-ruby @GeorgeStocker 引用的问题是关于= 运算符的效果,而我的问题是关于它在Ruby 中的实现。 【参考方案1】:

在技术意义上,变量只是指向对象的指针。这并没有什么特别之处,但是对现有对象的简单变量分配不涉及任何方法调用或发送消息。

记住变量就在那里,以便程序员可以通过名称而不是某种内部标识符或内存位置来引用对象。所以这里有一点“魔力”,= 在分配作业时很特别,因为它的左右两边都有你可以做什么的规则。

您可以向某事物发送消息的唯一方法,即进行方法调用,是如果您以编译器可以理解的方式定义它。 x = 1 就足够了,这意味着x 指的是有问题的Fixnum。

请注意,Ruby 解释器需要确定 x 是指变量还是方法调用,因为 x= 可能是在评估 this 的对象上下文中定义的方法。

例如:

class Example
  def x=(value)
    @x = value
  end

  def test
    # Equivalent to send(:x=, 1) because x= is a method
    x = 1

    # Is a variable definition because y= is not a method
    y = 2

    # Is always a method call because self is referenced.
    self.x = 3
  end
end

# Is a variable definition because x= is not defined in this context
x = 4

如果您的对象没有 x= 方法,则自动假定 x 是一个变量。

您不能有:= 消息,因为这意味着您可以用另一个对象替换一个对象,这是不允许的。一旦创建了一个对象,它就不能神奇地改变类型。为此,您需要创建不同对象的新实例。变量看起来只是改变类型,但实际上它们只是指向不同的对象。

简而言之,没有 := 方法调用,但可能有一些特殊的方法,例如 :x=,在非常特殊的情况下有效。

【讨论】:

另一件事:value = "newval" 总是被假定为一个变量(而不是一个方法),除非有一个明确的接收者。因此,如果您的上下文定义了:value=,那么您必须显式调用self.value = arg 才能访问该方法。 @acsmith 在代码编译后引入方法时会出现问题。好点子。 @CarySwoveland 一切都好。不过,程序员通过自言自语来解决问题并不少见! 那么,如果不使用 Class.new() 或使用 '=' 语法 为其赋值,就无法实例化对象,对吗? 对象一直被隐式创建:x(y: z) 至少创建一个,可能更多,因为至少创建了一个哈希 :y => z ,如果没有,:y 可能会被实例化' t 已经存在。我认为对于创建对象的内容没有任何硬性规定。它们就像 Ruby 世界中的水分子,你生活在它们的海洋中。请记住,偶数是对象,尽管它们非常轻量级,所以即使 x = 1 + 2 也可能创建三个对象,123

以上是关于Ruby 如何在语义上处理赋值?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Jenkins 上处理语义版本控制

如何检查两个 Java 类在语义上是不是相同?

如何隔离 Ruby 中的方法 - 多处理问题

如何使用 ruby​​ 的多重赋值为 void 变量赋值?

在 AJAX 更新 Ruby on Rails 6 后,语义 UI 模式不会重新打开

深入了解 Flink 如何实现端到端的 Exactly-Once 处理语义