数组
Ruby的数组不是homogen的,可以保存不同的类型,包括数组
a = [ 3.14159, "pie", 99 ]
a.class => Array
a.length => 3
a[0] => 3.14159 # Index以0开始
a[3] => nil # 没有异常,返回nil
a[-1] => 99 # Index -1 返回最后一个元素
a[-a.length] => 3.14159 # 返回第一元素
数组的负Index和Python中的一样。
b = Array.new
b[100] = 1
a = [ 1, 3, 5, 7, 9 ]
a[3, 2] => [ 7, 9 ] # 从Index3开始,取2个
a[-3, 2] => [ 5, 7 ] # 从倒数第3个开始取2个
两种Ranges,在Pascal是见过其中一种, ..
1..100 表示1到100
1...100 表示1到99, 不包括100
-5..-1 表示-5, -4, -3, -2, -1
三点的Range不包括第二个端点
a[-3..-1] # 取最后3个元素
a[4..-2] # 从第4个元素起(从0开始计数),取到倒数第二个
如果Range的第二个端点在第一个前面,返回空数组[], 比如假设a只有5个元素,a[4..-2] => []
修改数组
a = [ 1, 3, 5, 7, 9 ]
a[2, 2] = 'cat' => a = [ 1, 3, 'cat', 9 ] # 删除左边[2, 2]选定的区域,插入右边的元素
a[2, 0] = 'dog' => a = [ 1, 3, 'dog', 'cat', 9 ] # 如果左边选定的区域为空,相当于插入元素
a[1, 1] = [ 9, 8, 7 ] => a = [ 1, 9, 8, 7, 'dog', 'cat', 9 ] # 右边为数组,逐个插入
a[0..3] = [] => a = [ 'dog', 'cat', 9 ] # 右边为空,相当于删除
a[5..6] = 99, 98 => a = [ 'dog', 'cat', 9, nil, nil, 99, 98 ]
Block
Ruby的Block中的变量的Scope比较混乱,看下面这段代码
a = 1, 2
b = 'cat'
a.each { |b| c = b * a[1] }
c是Block中的局部变量,而a,b是Block之外上两行定义的a和b。在执行这段代码后,b = 2, c未定义,
defined?(c)返回nil. 规律是,如果变量已定义,则用之,否则是Block的局部变量,在Block之外不可见。这一特性可能在Ruby2.0中修改。
Block的最后一个表达式的值作为yield的返回值。
Iterator
遍历在Ruby中有多种不同的实现方式
each对每个元素做点什么
[1, 2, 3, 4].each { |x| puts x }
collect对每个元素调用Block,用返回的值重新组成数组
[1, 2, 3, 4].collect { |x| x+1 } => [2, 3, 4, 5]
["A", "B"].collect { |x| x.succ } => ["B", "C"]
collect类似maplist, 只不过maplist的函数参数在这里是Block。
inject对每个元素调用Block计算值,并用一个变量将值传递到Block的下次调用。
[1, 2, 3, 4].inject(0) { |sum, x| sum + x } => 10
执行过程如下
sum = 0 # inject的输入参数
for each element x
sum = yield(sum, x)
end
return sum
所有的each可以方便的用inject实现
[1, 2, 3, 4].inject(0) { |s, x| puts x } 等效于 [1, 2, 3, 4].each { |x| puts x }, 除了返回值不同
求一个数组里所有数的乘积
[1, 2, 3, 4].inject(1) { |prod, x| prod * x }
也可以写成
[1, 2, 3, 4].inject { |prod, x| prod * x }
如果inject不带参数,prod先为第一个元素,从第二个元素开始遍历。
inject这个名字不是很恰当,还不如用accumulate。
block_given?函数判断是否带有Block调用
函数参数
def foo(*args)的参数个数是任意,*args收集参数作为一个数组,比如foo(1, 2, 3), args = [1, 2, 3]
Proc
Block是匿名的,如果一个函数的最后一个参数名以&打头,那么要求一个Block。Block还可以用lambda转化为Proc对象,Proc可以用call方法调用。
proc = lambda { |x, y| x + y }
proc.call(1, 2) => 3
def n_times(thing)
lambda { |n| n * thing }
end
p1 = n_times(23)
p1.call(3) => 69
p2 = n_times("Hello ")
p2.call(3) => "Hello Hello Hello "
n_times的参数thing在新生成的Proc中还存在,这种性质在其他语言中称为Closure。
转载请保留
http://www.blogjava.net/xilaile/archive/2007/05/06/115624.html