将块传递给方法的替代方式?

时间:2014-05-12 23:02:55

标签: ruby

以这种方式将块传递给方法时会调用什么:.map(&:capitalize)

它只是语法糖吗?速记?你能用它做任何其他事吗?

1 个答案:

答案 0 :(得分:2)

Ruby中的每个方法都有一个特殊的“块”插槽,这不是一个普通的参数。这是因为将一个块恰好传递给一个方法是最常见的用例,Ruby会优化它¹。 &符号用于表示在该插槽内特定传递的内容。

def with_regular_argument(block)
  block.call
end

def with_block_argument(&block)
  block.call
end

with_regular_argument lambda { puts 'regular' }    # regular
with_block_argument { puts 'block argument' }      # block argument

调用方法时也可以使用该符号。这样,您可以将任何对象作为块传递,并在其上调用to_proc以将其强制转换为Proc

def to_proc
  proc { puts 'the main object was converted to a Proc!' }
end

with_block_argument &self    # the main object was converted to a Proc!

请注意,如果您调用了with_regular_argument

,则不会执行强制操作
begin
  with_regular_argument self
rescue => error
  puts error.message            # undefined method `call' for main:Object
end

Symbol类实现to_proc。它基本上是这样的:

class Symbol
  def to_proc
    proc { |receiver| receiver.send self }
  end
end

那么,以下几行如何运作?

enumerable.map &:to_s
  1. 我们在特殊区块位置传递:to_s。这由&表示。
  2. 在符号上使用&来电to_proc
  3. to_proc返回Proc,将:to_s发送到第一个参数。
  4. 然后将此Proc传递给特殊块广告位中的map方法。
  5. 产生的每个元素都成为信息的接收者。
  6. 它几乎相当于:

    enumerable.map { |receiver| receiver.send :to_s }
    

    ¹耶胡达卡茨。 Ruby不是面向可调用的语言(它是面向对象的)。 Blog post