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