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

Ruby different behavior depend of block type

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

带花括号的块只是实现并且 p 打印 one Ruby is a COOL language!:

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

刚刚跳过 do/end 中的 'same' 代码片段,p 显示 Enumerator <Enumerator: "rubyisacoollanguage":gsub(/(ruby)(is)(a)(cool)(language)/)>:

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

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

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

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

Ruby 松散的语法规则的问题在于,有时它会在块属于谁时被绊倒。由于歧义,pgsub 都可以 "own" 该块。 do 方法被分配给 p,而 { ... } 方法被固定在 gsub

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

如果有歧义,最好根据解释的方式避免,而是更具体:

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

p rv

这里rv =不能拿块所以它不会最终无意中抓住它。

您也可以这样做:

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

你在哪里非常清楚谁得到了什么。

Ruby 通常会给你两种表达同一事物的方式。 blockp 调用关联,而不是 gsub 调用。

运算符优先级。

Why does it happen?

因为 {} 和 do/end 有不同的优先级。 {} 是 "stronger"。如 "is associated to the nearest method call"。所以这个

p foo {
  something
}

是这样看的

p (foo {
  something
})

而do/end是这样的

p(foo) do
  something
end

No error, just skip part of the code

是的,由于 ruby 的另一个特点。这是 "you can pass a block to ANY method. It is then that method's responsibility to use or ignore it." 这里 p 不期望一个块并简单地忽略它。