Ruby书中的代码块

Code block from Ruby book

我在Coppers的书《开始的Ruby》中找到了一个代码块的例子。这应该是处理代码块的自定义方法的示例吗?

1
2
3
4
5
  def each_vowel(&code_block)
    %w{a e i o u}.each { |vowel| code_block.call(vowel) }
  end

  each_vowel { |vowel| puts vowel }

我就是不明白这是怎么回事。他是否正在将一个代码块发送到另一个代码块?

有点不对劲。我得到了each从数组中获取特定的项,一次一个,并将其放入vowel变量中,但是接下来会发生什么呢?


是的,在另一个块中执行一个块是正确的。&code_block是一种将块转换为可执行proc对象的特殊方法。在方法定义中,code_block现在引用一个proc对象,当使用call方法执行时,该对象基本上运行与方法调用关联的块中的代码(在本例中是{ |vowel| puts vowel }

但这不是执行关联块的唯一方法。另一种非常常见的方法是使用yield关键字。在这里,一旦到达yield关键字,就执行块。

1
2
3
4
5
def each_vowel
  %w{a e i o u}.each { |vowel| yield(vowel) }
end

each_vowel { |vowel| puts vowel }

注意,在这种情况下,在方法签名中不需要使用&code_block。Yield始终可以访问相关的块。但是,如果希望以proc对象的形式访问块,则需要在参数列表的末尾指定类似于&code_block的内容。


%w{a e i o u}是单词数组的Ruby语法。相当于['a', 'e', 'i', 'o', 'u']

所以上面的代码可以写成:

1
2
3
4
5
  def each_vowel(&code_block)
    ['a', 'e', 'i', 'o', 'u'].each { |vowel| code_block.call(vowel) }
  end

  each_vowel { |vowel| puts vowel }

所以这段代码对数组(.each中的每个元素所做的就是,它调用以元素为参数的块(code_block.call)。

.each本身接受一个块(在本例中它是{ |vowel| code_block.call(vowel) }并为数组中的每个元素调用它。

each_vowel { |vowel| puts vowel }调用前面定义的方法,其中块{ |vowel| puts vowel }作为输入参数。它可能更熟悉括号:

1
  each_vowel() { |vowel| puts vowel }

但是在Ruby中,括号是可选的,特别是当一个方法不需要参数时(一个块不算参数)。