【问题标题】:Official expansion of ||= conditional assignment operator||= 条件赋值运算符的正式扩展
【发布时间】:2012-08-30 12:30:47
【问题描述】:

我想强调的是,我正在寻找 实际 ||= 运算符由 Ruby 1.9.3 解释器扩展的方式,而不是 看起来 的扩展方式基于它的行为。我真正希望的是有人了解实际的解释器来源,遗憾的是我可能无法完成这项任务。我发现的唯一似乎可以检查此问题的资源已过时:“A short-circuit (||=) edge case”。

我上面提到的资源似乎表明 x ||= y 到 x = x || y 的“官方”扩展在 1.9 之前的解释器版本中要么不准确,要么存在错误。无论如何,所指示的边缘情况似乎已被平滑。上述资源声称x || x = y 或x or x = y“更准确”。然而,这两种方法都不正确,因为当 x 是以前未声明的全局变量时,它们不起作用:

[11:04:18][****@asha:~]$ irb
1.9.3-p194 :001 > a || a = 3
    NameError: undefined local variable or method `a' for main:Object
1.9.3-p194 :002 > b or b = 3
    NameError: undefined local variable or method `b' for main:Object
1.9.3-p194 :003 > c = c || 3
    => 3 

因此,就这些示例而言,至少在 1.9.3 中,x = x || y 扩展似乎是正确的。不过,重申一下我最初的观点,我真的很想看到一些真正权威的资源来解决这个问题,嗯,权威的,而不是像我(和其他人)所做的那样以传闻的方式。

【问题讨论】:

标签: ruby


【解决方案1】:
x ||= y

是

的简写形式
x || x = y

如果x 不是nil 并且x 不是false,则由于|| 运算符的短路评估,分配将有位置。

【讨论】:

    【解决方案2】:

    编辑:这篇文章是关于规范的,阅读 cmets 以获得不太理想的“实施故事”


    Ruby draft spec (PDF) section 11.4.2.3.2 相当明确地定义了它(即使相当难以解释);让我们用 c ||= 3 做一个(理论上有点松散)的例子;

    a) 将变量评估为变量引用(参见 11.5.4)。设 V 为结果值。

    V设置为c的值

    b) 评估运算符表达式或方法调用无括号。令 W 为结果值。

    W 设置为3。

    c) 令 OP 为 assignment-operator 的 assignment-operator-name。

    OP 设置为||

    d) 令 X 为 V OP W 形式的运算符表达式。

    X 设置为c || 3。

    e) 设 I 为 abbreviated-variable-assignment-expression 或 abbreviated-variable-assignment-statement 的变量。

    我设置为引用c。

    f) 计算一个单变量赋值表达式(参见 11.4.2.2.2),其中变量为 I,运算符表达式为 X。

    c = c || 3 被评估。

    g) 缩写变量赋值的值是评估的结果值。

    分配的结果是3。

    换句话说,扩展 c = c || 3 是正确的(不包括 1.9 之前的错误)。

    【讨论】:

    • (愚蠢的编辑时间限制)酷,这比某些家伙的博客文章更令人欣慰。然而,一些后续问题:1)1.9.3 解释器在多大程度上符合该标准草案? (“草稿”这个词让我有点担心) 2)如果我正确阅读了关于全局变量引用的部分,a)没有问题。但是,11.5.4.5(类变量)似乎表明 ||= 运算符不应与尚未分配值的类变量一起使用 - 但它确实如此,扩展也是如此。所以我在这一点上有点困惑。
    • 哦哦。尽管我接受了正确链接到标准的答案,但在这种情况下,标准显然是错误的。 stackoverflow.com/questions/2989862/… 对 x = x || y 扩展理论有一个很好的反例,因为如果 x 已经“真实”,则显然不会发生任何赋值。我也希望我在问这个问题之前看到ruby-forum.com/topic/151660,因为那样我可能不会添加到关于这个主题的大量帖子列表中。
    • 规范没有专门针对||=。据我了解,这是 MRI 中的一个特例(以及其他实现,为了兼容性)。
    • @echristopherson:这就是问题所在。 ||= 和 &&= 是特例,但它们在规范中不是特例,这使得规范或每个 Ruby 实现都出错。由于该规范是专门编写的,目的是所有现有的 Ruby 实现都应该自动兼容而无需更改,因此该错误显然在规范中。
    猜你喜欢
    • 2018-06-09
    • 2011-09-18
    • 2015-06-06
    • 2011-03-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-07-16
    • 1970-01-01
    相关资源
    最近更新 更多