您的位置:首页 > 编程语言 > Ruby

Ruby-自定义迭代器与yield方法

2015-11-13 11:02 645 查看
对于迭代器each_with_index应该不是很陌生:

%w(dog cat parrot).each_with_index do |animal,index|
puts ">> #{animal} is number #{index}"
end
#>> dog is number 0
#>> cat is number 1
#>> parrot is number 2


那么如果要自定义一个迭代器 each_with_custom_index, 要求对index进行管理,即自定义index的起点和步距(如下图),该怎么做呢?

%w(dog cat parrot).each_with_custom_index(3,2) do |animal,index|
puts ">> #{animal} is number #{index}"
end
#>> dog is number 3
#>> cat is number 5
#>> parrot is number 7


首先要知道%w这个返回的是一个数组:

irb(main):001:0> %w(dog cat parrot).class
=> Array


然后我们找出Array的继承类和模块:

irb(main):002:0> Array.ancestors
=> [Array, Enumerable, Object, Kernel, BasicObject]
irb(main):003:0> Array.included_modules
=> [Enumerable, Kernel]


对于each_with_index,有很大可能是在Enumerable模块中定义的,Enumerable被include在Array类里,所以Array的实例对象才能直接调用each_with_index,我们可以验证一下我们的猜想:

irb(main):005:0> Enumerable.instance_methods.respond_to? :each_with_index
=> true


当然,完全没有必要去这样做,因为可以直接Google出each_with_index这个方法,找ruby对应的API,就可以知道在哪个模块实现的,但作为新手,这样只是帮助梳理一下思路 :)

那么我们就在Enumerable中定义新方法each_with_custom_index:

module Enumerable
def each_with_custom_index(start,offset)
self.each_with_index do |start,index|
yield name, start+index*offset
end
end
end

%w(dog cat parrot).each_with_custom_index(3,2) do |animal,index| puts ">> #{animal} is number #{index}" end #>> dog is number 3 #>> cat is number 5 #>> parrot is number 7


最终还是利用了each_with_index方法,只不过把这种实现封装了Enumerable模块中,以后只要是mix-in了这个模块的实例对象都可以实现这个功能。

yield方法

yield这个函数能回调参数到与方法名相同的代码块中执行,也就是说,它能连接同名的块与方法,举个例子:

def Haha
a=1; b=2
yield a,b
end

Haha do |a,b|
puts "a=#{a},b=#{b}"
end
#=>a=1,b=2

Haha {|a,b| puts "a=#{a},b=#{b}"}
#=>a=1,b=2


上述代码块Haha用了两种写法,a和b都是在Haha方法内定义,然后我们看一下执行顺序:

def Haha
puts "方法内"
a=1; b=2
yield a,b
puts "方法内"
end

Haha do |a,b|
puts "代码块内"
puts "a=#{a},b=#{b}"
puts "代码块内"
end
#=> 方法内
#=> 代码块内
#=> a=1,b=2
#=> 代码块内
#=> 方法内


首先是在方法内执行,当执行到yield方法后转到同名的Haha代码块内,执行完代码块后继续执行方法内的代码。

关于块,更多戳这里:http://www.runoob.com/ruby/ruby-block.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  yield