重载Yield函数



我注意到在学习Ruby的过程中,每个方法的这两种用法都可以工作并产生相同的输出,我想知道Ruby是如何实现这一点的(以及我如何为自己的函数实现这一点):

my_array = [["hello","goodbye"],["picture","perfect"]]
my_array.each do |array|
  puts array[0] + " " + array[1]
end
my_array.each do |first, second|
  puts first + " " + second
end

我的理解是,当编写接受代码块的方法的定义时,yield方法被用来将参数传递给代码块并调用代码块。但是如何利用yield方法,使其根据所提供的代码块传递不同的参数呢?在示例中,当在块中使用两个参数(即first, second)时,yield方法传递单个数组元素,当在块中使用一个参数(即array)时,它传递数组本身。

eachyield在这里都没有做任何特别的事情,这就是块参数的工作方式。考虑这个简单的例子:

def f(x) yield x end

,现在我们可以看到发生了什么:

>> f([1,2]) { |a| puts a.inspect }
[1, 2]
>> f([1,2]) { |a, b| puts "#{a} - #{b}" }
1 - 2
>> f([1,2]) { |a, b, c| puts "#{a} - #{b} - #{c}" }
1 - 2 - 

你会在赋值中看到类似的析构:

a, b = [1, 2]

你也可以显式地使用splat:

a, b = *[1, 2]

或者像这样:

def g(x) yield *x end
g([1, 2]) { |a, b| puts "#{a} - #{b}" }

假设块知道它将被给定的东西类型,因此块可以很好地解压缩参数。请注意,g函数必须知道它的参数是可溅射的(即一个数组),但f没有。f很好地将"x是什么类型的东西"逻辑放在对f的调用中,g将一半的逻辑隐藏在自己内部。当您在Hash上使用Enumerable方法时,差异变得明显:

{ :where => :is, :pancakes => :house? }.map { |k, v| ... }

Enumerable#map不需要知道哈希在键/值两个元素数组中工作,它只是传递东西,让其他人去担心细节。

最新更新