Ruby不同的行为取决于块类型

时间:2018-07-13 19:27:22

标签: ruby block

美好的一天。 我对同一代码块的行为不同,具体取决于块语法大括号或do / end的类型。跳过do / end的块而没有任何错误通知:

带有大括号的块仅实现,p打印one Ruby is a COOL language!

p "rubyisacoollanguage".gsub(/(ruby)(is)(a)(cool)(language)/) {
   "one " + $1.capitalize + " %s %s %s %s!" % [$2,$3,$4.upcase,$5]
}

do / end中的“相同”代码段刚刚被跳过,p向我展示Enumerator <Enumerator: "rubyisacoollanguage":gsub(/(ruby)(is)(a)(cool)(language)/)>

p "rubyisacoollanguage".gsub(/(ruby)(is)(a)(cool)(language)/) do
    "two " + $1.capitalize + " %s %s %s %s!" % [$2,$3,$4.upcase,$5]
end

我认为它是由于p而发生的,在第二种情况下它消除了障碍。当我在块中添加p时,事情就会变得很清楚。第一个块的数据打印了2次,而第二个块的数据根本没有打印。

p "rubyisacoollanguage".gsub(/(ruby)(is)(a)(cool)(language)/) {
   p "one " + $1.capitalize + " %s %s %s %s!" % [$2,$3,$4.upcase,$5]
}
p "rubyisacoollanguage".gsub(/(ruby)(is)(a)(cool)(language)/) do
    p "two " + $1.capitalize + " %s %s %s %s!" % [$2,$3,$4.upcase,$5]
end

对我来说,这是非常奇怪且不可预测的行为。没有错误,只需跳过部分代码。为什么会发生?

3 个答案:

答案 0 :(得分:5)

  

为什么会发生?

因为{}和do / end的优先级不同。 {}是“更强”的。如“与最近的方法调用相关联”。所以这个

p foo {
  something
}

这样看。

p (foo {
  something
})

做/结束就是这样

p(foo) do
  something
end
  

没有错误,只需跳过部分代码

是的,由于红宝石的另一个特征。这就是“您可以将块传递给ANY方法。然后,使用或忽略它是该方法的责任。”这里p不需要块,只是忽略它。

答案 1 :(得分:2)

Ruby宽松的语法规则的问题在于,有时它会误解该块属于谁。由于模棱两可,pgsub都可以“拥有”该块。 do方法被分配给p,而{ ... }方法被固定在gsub上。

这可能是由于某些运算符优先级类型规则所致,尽管由于该块本身不是运算符,所以我不确定现在是否可以找到该特定行为的引用。

在有歧义的地方,最好避免依赖于它的解释方式,而应更加具体:

rv = "rubyisacoollanguage".gsub(/(ruby)(is)(a)(cool)(language)/) do
  "two" + $1.capitalize + " %s %s %s %s!" % [$2,$3,$4.upcase,$5]
end

p rv

rv =不能挡住它,所以它不会最终无意间被抓住。

您也可以这样做:

p(
  "rubyisacoollanguage".gsub(/(ruby)(is)(a)(cool)(language)/) do
    "two" + $1.capitalize + " %s %s %s %s!" % [$2,$3,$4.upcase,$5]
  end
)

您要在哪里清楚地弄清谁得到了什么。

答案 2 :(得分:2)

Ruby通常为您提供两种表达同一事物的方法。 blockp调用关联,而不与gsub调用关联。

运算符优先级。