Wednesday, October 22, 2008

(4)自定义迭代器

定义一个迭代器类似于方法调用,只不过我们这里是调用中的代码。实现这一功能需要使用yield方法,下面是一个例子,她非常简单实现了调用两次中代码的功能:
def twice
yield
yield
end

迭代器可以有参数,参数用括号包含并用逗号分隔,当然按照方法定义的规则,括号是可以省略的。下面是一个例子:
# 下面的方法定义了一个迭代器,每次迭代输出一个计算值,输出的结果是m*i+c,要求
# i的值必须在0到n-1之间

def sequence(n, m, c)
i = 0
while(i < n) #循环n次
yield m*i + c # 调用块,并把计算结果传递给块参数
i += 1 # 每次i的值加1
end
end

# 下面是调用的方法,结果将打印 1, 6, 和 11
sequence(3, 5, 1) {|y| puts y }

下面是另一个例子,它传递了两个参数,值得注意的是在这个迭代器中使用了另一个迭代器:
def circle(r,n)
n.times do |i| # 注意这里使用了另一个迭代器
angle = Math::PI * 2 * i / n
yield r*Math.cos(angle), r*Math.sin(angle)
end
end

# 调用这个迭代器将打印:
# (1.00, 0.00) (0.00, 1.00) (-1.00, 0.00) (-0.00, -1.00)
circle(1,4) {|x,y| printf "(%.2f, %.2f) ", x, y }

yield关键字非常类似于方法调用,但是你不能像方法一样给块参数传递另一个块。有时候你定义了一个迭代器,但是如果在调用它的时候没有给出块部分,这回引发一个异常。你可以定义一个缺省行为,在每一个给出块的时候执行你的缺省行为。这需要用到方法block_given?或者iterator?,这两个方法是kernel中定义的方法,所以你可以当作全局函数那样使用:
# 根据公式 m*i+c迭代
# 如果块存在yeild值
def sequence(n, m, c)
i, s = 0, [] # 初始化变量
while(i < n) # 循环n次
y = m*i + c # 计算值
yield y if block_given? # Yield, 如果有块
s << y # 存储值
i += 1
end
s # 返回数组
end

No comments: