Wednesday, October 08, 2008

(2)块 与 迭代 (block and Iterator)

在Ruby中调用 整数 的方法非常简单,实际上大多数程序员经常这样做。比如下面的例子:
3.times { print "Ruby! " }   # 打印 "Ruby! Ruby! Ruby! "
1.upto(9) {|x| print x } # 打印 "123456789
times 和 upto 是整数对象实现的方法,他们是一种特殊的方法我们称之为迭代,花括号{}中的内容我们称之为,结合迭代他们实现了对块内部分进行循环的操作,实际上迭代和块是Ruby的一个特性,尽管Ruby语言也提供了原生的while loop 循环,但是跟通用的方法是使用块和迭代。
不只整数有迭代方法,比如数组Array(以及任何“枚举”类的类型)都有一个each迭代方法,这个方法会循环调用内的方法并且每次循环将数组内的一个元素传递给块内的运行逻辑。

a = [3, 2, 1] # 我们定义一个数组
a[3] = a[2] - 1 # 类用方括号下标的方法 查询并给新的数组元素赋值
a.each do |elt| # each 是一个迭代。这个块有一个参数名为 elt
print elt+1 # 打印 "4321"
end # 这里使用 do/end 来定义块而不是用括号{}


另一个例子:
a = [1,2,3,4]                # 定义一个数组
b = a.map {|x| x*x } # 对块内的内容求平方: b = [1,4,9,16]
c = a.select {|x| x%2==0 } # 选择数组中的偶数: c is [2,4]
a.inject do |sum,x| # 计算数组中所有数的合计值 => 10
sum + x
end

Ruby 中的列表 Map 也有迭代方法each.不过它不同于数组是通过整数下标的方式取值,它是一个键/值对的列表,取值是通过在方括号内放置的方式。比如下面的例子:
h = {                         # 我们定义一个新的列表
:one => 1, # 通过=>标记来给键 赋值: key=>value
:two => 2 # 每个键值对用逗号分隔
}
h[:one] # => 1. 通过键访问值,其结果为1
h[:three] = 3 # 在列表中增加一个新的键值对
h.each do |key,value| # 通过键/值对迭代
print "#{value}:#{key}; " # 通过把对象放在#{}内将其转换为字符串
end
Ruby 中的块与迭代的特性非常强大,不只是在循环中使用甚至在一个方法中只调用一次也是非常有用的:

File.open("data.txt") do |f| # 打开指定的文件把字节流传给块
line = f.readline # 读取字节流的内容
end # 块结束的时候字节流自动被关闭

t = Thread.new do # 在一个新的线程里运行这个块
File.read("data.txt") # 在程序后台读取文件
end # 文件的内容被读入一个新的线程中。

顺便提一下前面用到的#{} 方式,他可以把任何对象转换为字符串,实际上它调用了每一个对象都是先的to_s 方法,我们称这种方法为字符串插入string interpolation

No comments: