gr8vyguy@Blogjava

Ruby学习笔记3,第四章

数组
  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比较混乱,看下面这段代码

= 12
= '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

posted on 2007-05-06 15:18 gr8vyguy 阅读(620) 评论(0)  编辑  收藏


只有注册用户登录后才能发表评论。


网站导航:
 
<2007年5月>
293012345
6789101112
13141516171819
20212223242526
272829303112
3456789

导航

统计

公告

  • 转载请注明出处.
  • msn: gr8vyguy at live.com
  • 常用链接

    留言簿(9)

    随笔分类(68)

    随笔档案(80)

    文章分类(1)

    My Open Source Projects

    搜索

    积分与排名

    最新评论