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