Ruby内联while与while end的区别

6
为什么这个代码能够运行:
a = [1, 2, 3]
while n = a.shift
  puts n
end

虽然这样做不行:

a = [1, 2, 3]
puts n while n = a.shift

只有在提前初始化 n 的情况下才能正常工作:

a = [1, 2, 3]
n = nil
puts n while n = a.shift

https://dev59.com/v3zaa4cB1Zd3GeqPP26L/ - Jörg W Mittag
与 LALR 下降相关的解析器问题会影响 Ruby 后置条件。它们是错误,但没有人会为它们打开错误报告。请参见 此相关答案,其中有关于 :if_mod 标记的类似问题。 - Todd A. Jacobs
3个回答

4

一般来说,这是一个解释器问题,在具有本地变量冒泡的语言(如JavaScript)中不会出现。

解释器(从左到右阅读)在任何提及右操作数n之前就已经遇到了它。

我越想,越确信这是Ruby解释器中的一个错误。正如@Cary所指出的那样,控制流实际上是相同的:

a = [2, 3]
n = 1
puts n while n = a.shift
#⇒ 2
#⇒ 3

在上面的输出中没有任何关于1的迹象。

好的解释。你可能想再添加一个情况:第二个例子之前加上 n = 0 - Cary Swoveland
谢谢。实际上,第二个例子中的 n = 0 前置,与第一个例子在伪代码中写得 完全 相同,这就是为什么我决定省略它的原因。更新:哦,等等。我会加上的,谢谢。 - Aleksei Matiushkin
我提出这个建议是因为我认为有些读者可能会认为在那种情况下会打印出 0 - Cary Swoveland
@CarySwoveland 非常感谢,其实我之前的回答有点混淆,我已经完全重写了。 - Aleksei Matiushkin
控制流是无关紧要的。在puts n中,n是一个方法调用,因为此时从左到右的解析器中没有定义名为n的局部变量。这只是一个局部变量的怪癖,需要特殊处理。 - cremno
这不是解释器中的一个错误,而是LALR自上而下分析器在处理后置条件标记时的错误特性。 - Todd A. Jacobs

1

关于:puts n while n = a.shift

它会先解析puts n,但此时n未定义。Ruby是一种动态类型语言;您不需要显式声明变量类型,但应为变量赋值。

例如:

irb(main):027:0> xyz
NameError: undefined local variable or method `xyz' for main:Object
irb(main):028:0> xyz = 1
=> 1

它首先会尝试解析puts n,而不是立即执行。 - Aleksei Matiushkin

1

n在你尝试第一次puts时是未定义的。该条件及相应的shift只有在puts被评估后才会被检查。一个替代方案可以按照你的期望工作。

a = [1, 2, 3]
puts a.shift while a.length > 0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接