Iterator
定义
A Ruby iterator is simple a method that can invoke a block of code.
- Block 一般是跟着 method 出现的, 并且 block 中的代码不一定会执行
- 如果 method 中有 yield, 那么它的block 中的代码会被执行
- Block 可以接收参数,和返回 value
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
def two_times yield yield end two_times { puts "Hello" } # Hello # Hello def fib_up_to(max) i1, i2 = 1 . 1 while i1 <= max yield i1 i1, i2 = i2, i1 + i2 end end fib_up_to( 1000 ) { |f| print f, " " } # 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 |
上面代码中的 yield 之后的 i1 会作为 parameter 传入到 block 中, 赋值给 block 的 argument f。
Block 中可以有多个 arguments.
常见的 iterator
each
each is probable the simplest iterator - all it does is yield successive elements of its collection.
1
2
3
4
5
6
7
|
[ 1 , 3 , 5 , 7 , 9 ]. each { |i| puts i } # 1 # 3 # 5 # 7 # 9 |
find
A blocl may also return a value to the method. The value of the last expression evaluated in the block is passed back to the method as the value of the yield.
1
2
3
4
5
6
7
8
9
|
class Array def find each do |value| return value if yield (value) end end end [ 1 , 3 , 4 , 7 , 9 ].find { |v| V * V > 30 } # => 7 |
collect (also known as map)
Which takes each element from the collection and passes it to the block. The results returned by the block are used to construct a new array
1
|
[ "H" , "A" , "L" ].collect { |x| x.succ } # => ["I", "B", "M"] |
inject
The inject method lets you accumulate a value across the members of a collection.
1
2
3
4
5
6
7
8
|
[ 1 , 3 , 5 , 7 ].inject { |sum, element| sum + element } # => 16 # sum = 1, element = 3 # sum = 4, element = 5 # sum = 9, element = 7 # sum = 16 [ 1 , 3 , 5 , 6 ].inject { |product, element| product*element } # => 105 |
If inject is called with no parameter, it uses the first element of the collections as the initial value and starts the iteration with the second value.
上面代码的另一种简便写法:
1
2
|
[ 1 , 3 , 5 , 7 ].inject(:+) # => 16 [ 1 , 3 , 5 , 7 ]/inject(:*) # => 105 |
Iterator 和 I/O 系统的交互
Iterators 不仅仅能够访问 Array 和 Hash 中的数据, 和可以和 I/O 系统交互
1
2
3
4
5
|
f = File .open( "testfile" ) f. each do |line| puts "The line is: #{line}" end f.close |
produces:
The line is: This is line one
The line is: This is line two
The line is: This is line three