Ruby 使用圆括号的方法调用抛出语法错误

Ruby method call using round brackets throwing syntax error

我无法理解为什么我不能用圆括号调用 select。

a = [1,2,3]
a.select {|v| v.is_a?(Integer)}  # works
a.select({|v| v.is_a?(Integer)}) # syntax error, unexpected '|', expecting '}

据我所知,select 是一种常规方法。

Array.method_defined? :select # true
Array.method_defined? :is_a?  # true

虽然圆括号对于 ruby 中的方法是可选的。
在下面的情况下,圆括号没有区别。

a.reverse() == a.reverse #true

我正在使用 ruby 2.2.1.
有什么想法吗?

圆括号是一种将参数传递给方法的方式,而波浪括号(或 do/end)是一种将块传递给方法的方式。它们不可互换。

波浪括号也可用于在 ruby 中创建哈希,这可能会造成一些混淆。

一些 ruby 方法可以接受参数和一个块,在这种情况下,您可以在波浪形括号之前使用圆括号:E.G.

open("ChangeLog") { |f|
    f.slice_before(/\A\S/).each { |e| pp e }
}

你不能通过这样的 synatx 传递一个块,你必须这样做:

a.select(&lambda { |v| v.is_a?(Integer) })

但通常你会这样做

a.select { |v| v.is_a?(Integer) }

相同
a.select() { |v| v.is_a?(Integer) }

即块在方法参数之外。

您还可以使用 'stabby' lambda 语法:

is_a_integer = ->(v) { v.is_a?(Integer) }
a.select(&is_a_integer)

因此,如果您想将一个块作为参数传递,您需要使用前缀 &,但出于无神论的原因,通常您会将块放在参数之外。

还要注意这些方法签名和调用方式之间的区别:

def call(&block)
  yield
end

call { 1 } # => 1

call(lambda { 1 }) # => ArgumentError

call(&lambda { 1 }) # => 1

def call(block)
  block.call
end

call { 1 } # => ArgumentError

call(lambda { 1 }) # => 1

call(&lambda { 1 }) # => ArgumentError

这是因为 lambda(和 Procs)是对象,因此我们可以 #call 来评估它们,但块不是并且可以使用 yield 关键字进行评估。 this blog post.

中有更多信息
lambda { 1 }.class # => Proc

带或不带括号,Array#select 不接受任何常规参数。然而,它接受块参数,但与方法调用关联的块始终放在括号之后,而不是括号内。

因此,调用:

a.select {|v| v.is_a? Integer }

也可以写成带括号的:

a.select() {|v| v.is_a? Integer }