`

ruby之enumerator

    博客分类:
  • ruby
阅读更多
由于版本的变更,1.8与1.9在许多地方是不一样的,API变化很大,虽然理论上说1.9要好,但是目前有很多应用还是基于1.8的,在windows玩ruby更是如此,因此必须得注意这两个版本间的一些区别,比如说Enumerator,首先Enumerator是一个类,代码如:
class Enumerator
    include Enumerable
.....

从上面这段代码可以看出,一个Enumerator对象就是一个Enumerable对象。但Enumerator与Enumerable目的是不同的,Enumerator目的在于枚举其它的对象。主要作用有两个:
一、作为Enumerable的代理对象。如to_enum等,返回一个不可变的代理Enumerator。

创建一个Enumerator对象也很简单,一般使用Object的to_enum或enum_for方法。to_enum返回一个可枚举但不可变的代理对象。

遍历数据加上索引时,
在1.8中
require 'enumerator'
foo.to_enum(:each_with_index).collect {|x,i| }

其中each_with_index是一个迭代器方法,即基于each_with_index的方式来迭代。
也可以这样:
require 'enumerator'
[1,2,3].enum_with_index.map{|x, i| }

在本人机子上装的是1.8.7,此版本已经内置了enumerator,所以不用require 'enumerator'也是可以运行的,包括each_slice也是。
在1.9中:
#map也可以
foo.collect.with_index {|x,i| }

两个版本的用法之所以不同,是因为在1.8中,collect或map返回的是一个Array对象,而在1.9中,返回的是却是Enumerator对象,只有Enumerator才有with_index方法,可能在1.8.7前的版本没有with_index,但是在1.8.7中是有with_index方法的。下面代码在1.8.7与1.9.1中都是可以运行的。
s="hi, how are you!"
s.each_char.with_index{ |args,arg|  }


二、作为外部迭代器使用。

Enumerator有个next方法,用于返回下一个元素,但是没有next?之类的方法,所以需要通过StopIterator异常来判断。而在1.9中(其实187也是可以的),Kernel.loop包含了一个隐式的rescue语句,如果此方法内部抛出StopIterator异常,循环将中止。如:
iterator = 9.downto(1);
loop do
  print iterator.next
end


关于内部迭代器与外部迭代器:
引用

一个基本的问题是决定到底由哪一方来控制迭代,是迭代器自身还是使用迭代器的客户代码?当客户代码控制迭代时,该迭代器被称为外部迭代器,反之当迭代器控制迭代时,该迭代器就是一个内部迭代器。那些使用外部迭代器的客户代码必须负责推进整个遍历过程并且显式的从迭代器中获得下一个元素。相比之下,在使用内部迭代器时,客户代码将一个操作传递给一个内部迭代器,该迭代器依次在每个元素上应用该操作。
外部迭代器比内部迭代器更灵活。比如,使用外部迭代器可以很容易的比较两个集合的相等性,如果用内部迭代器则不太可能。但是从另一个角度来看,内部迭代器更容易使用,因为它们已经为你定义好了迭代逻辑。
在Ruby中,像each这样的迭代器方法是内部迭代器,它们控制着迭代并且将值“推送”给那个与方法调用相关联的代码块。Enumerator枚举器具有一个each方法,可用于内部迭代,但是在Ruby1.9及其后的版本里,它们还能充当外部迭代器,客户代码可以使用next方法顺序的从一个枚举器中“取出"值。
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics