为什么 `each do` 会在带注释的方法定义中导致语法错误?

Why does `each do` cause a syntax error inside of an annotated method definition?

此代码:

private def not_ok
  collection.each do |x|
    puts x
  end
end

导致语法错误:

syntax error, unexpected keyword_do_block, expecting keyword_end

更新:这是使用 MRI Ruby 2.1.0。显然,此行为是特定于版本的,并已在更高版本中得到修复,包括 2.1.1 (!)。 (感谢@Amadan 和@JörgWMittag 指出这一点。)

为什么它会引发语法错误,如何在不将 do 块更改为 {} 块的情况下不给出语法错误?

为了比较,这些变体不会导致语法错误:

def ok
  collection.each do |x|
    puts x
  end
end

private def ok
  collection.each { |x|
    puts x
  }
end

private def ok
  each do |x|
    puts x
  end
end

自从了解到 def 表达式 return 可以传递给其他方法的符号后,我开始使用 private 单独注释我的更多方法,而不是单独使用 public 和 class 中的 private 部分(我觉得不太容易维护),并且 运行 多次遇到这个问题——任何时候方法包含 do/end块。

在旧版本的 Ruby 上,do/end 块似乎存在优先级问题。

您可以通过将 def 表达式的 return 值分配给一个变量,然后将该变量传递给对 Module#private:[=28= 的调用来解决这个问题]

var = def not_ok
  collection.each do |x|
    puts x
  end
end

private var

但是请注意,在旧版本的 Ruby 中,方法定义表达式的 return 值是实现定义的,因此您不知道上面的代码会做什么。 MRI、YARV、MacRuby、MagLev、JRuby 和 IronRuby 将 return nil 作为 def 表达式的结果,这将 raise 变成 TypeError,因为 Module#private 只需要 SymbolString 秒。 Rubinius 将 return 一个 CompiledMethod 对象表示该方法的编译代码,但同样,这将 raise 来自 Module#private.

TypeError

只有在 Ruby 的最新版本中,def 表达式才会计算为 Symbol,但是,在 Ruby 的那些最新版本中,优先级问题已解决也已修复,以便您的代码正常工作。

它适用于 YARV 2.2.0 和 JRuby-9.0.0.0-dev,但不适用于 JRuby 1.7.18 和 Rubinius 2.2.0(最后一个可能是一个错误,因为它声称与 Ruby 2.1.0).

兼容