ruby 迭代器使用方法_ruby专题

迭代器并不是Ruby发明的.它广泛地运用于各种面向对象语言.在Lisp中也有,只是不这么叫罢了.尽管如此,迭代器的概念并不为许多人熟悉,因此我们将在此做较为详细的介绍.

你知道,动词 iterate 的意思是做同一件事许多遍,因此,iterator就是用来将同一件事做许多次的东西.

当我们写代码时,我们需要各种环境下的循环.在C里,我们用for或者while.比如,

char *str;
for (str = "abcdefg"; *str != '\0'; str++) {
  /* process a character here */

C的for(...)语法提供了一种写循环的抽象方法,但测试 *str 是否为空(null)字符需要程序员了解字符串内部结构的细节.这让C看起来像低级(low-level)语言.更高级的语言是通过它们更具弹性的迭代器支持来实现的.考虑下面的 sh 命令行脚本:

#!/bin/sh
for i in *.[ch]; do  
      # ... here would be something to do for each file
done 

当前目录下所有的C源文件和头文件都将被处理,由命令行shell来一个个地捡取文件名并处理其中的细节.我想这是在比 C 要高的级别上工作,你觉得呢?

但有更多值得我们考虑的:在一种语言能够很好的给内建的数据类型的提供迭代器的同时,我们却仍需要回去用低级别的循环语言来实现对自己定义的数据类型的迭代,这真是让人失望.在面对对象编程时,用户经常一个接一个地定义数据类型,因此这是一个很严重的问题.

因此,所有的OOP语言都包含了一定的迭代器机制.某些语言为此提供一种特殊的类;Ruby则允许我们直接定义迭代器.

Ruby的String类型有很多有用的迭代器:

ruby> "abc".each_byte{|c| printf "<%c>", c}; print "\n"
<a><b><c>
   nil 

each_byte 是个用于字符串中每个字符的迭代器.每个字符串由局部变量c代替.这可以翻译为类似C的代码...

ruby> s="abc";i=0
   0
ruby> while i<s.length
    |    printf "<%c>", s[i]; i+=1
    | end; print "\n"
<a><b><c>
   nil 

...然而, each_byte 迭代器在概念上要简单些,而且即使以后 String 类突然有所改变也应该可以照样工作.使用迭代器的一个好处便是在此类改变中仍然可以保持健壮;一般的,它的确是好代码的一个特点.(好,请有点儿耐心,我们将会马上谈到什么是类)

String的另一个迭代器是 each_line.

ruby> "a\nb\nc\n".each_line{|l| print l}
a

c
   nil 

采用迭代器,这将很轻松的取代C的大多数编程效果(找换行符,生成子串等等)

前面出现的for语句通过each迭代器实现迭代功能. String的each和each_line的工作原理差不多,让我们用for重写上面的例子:

ruby> for l in "a\nb\nc\n"
    |   print l 
    | end
a

c
   nil 

我们可以用retry流程控制语句连接迭代循环,它会从头执行当前循环的迭代.

ruby> c=0
   0
ruby> for i in 0..4
    |   print i
    |   if i == 2 and c == 0
    |     c = 1
    |     print "\n"
    |     retry
    |   end
    | end; print "\n"
012
01234
   nil 

yield有时会在一个迭代器的定义中出现. yield将流程控制移至传递给迭代器的代码域(这将会在过程对象那一节介绍更多的细节).下面的例子定义了一个repeat迭代器,会依参数的设置执行多次代码域.

ruby> def repeat(num)
    |   while num > 0
    |     yield
    |     num -= 1
    |   end
    | end
   nil
ruby> repeat(3) { print "foo\n" }
foo
foo
foo
   nil 

利用retry,我们可以定义一个有while相同作用的迭代器,虽然在实际应用中它太慢了.

ruby> def WHILE(cond)
    |   return if not cond
    |   yield
    |   retry
    | end
   nil
ruby> i=0; WHILE(i<3) { print i; i+=1 }
012   nil 

搞懂什么是迭代器了吗?有一些限制,但你可以写自己的迭代器;实际上,当你定义一个新的数据类型时,为它定义一个合适的迭代器经常也很方便.这样看来,上面的例子并不是很好用.在我们理解了类以后,我们可以讨论讨论更具实际意义的迭代器.

时间: 2024-07-31 17:52:43

ruby 迭代器使用方法_ruby专题的相关文章

ruby 流程控制 方法_ruby专题

这章我们将讨论更多的Ruby流程控制. case 我们用case语句测试有次序的条件.正如我们所见的,这和C,Java的switch相当接近,但更强大. ruby> i=8 ruby> case i     | when 1, 2..5     |   print "1..5\n"     | when 6..10     |   print "6..10\n"     | end 6..10    nil  2..5表示2到5之间的一个范围.下面的表达

使用rbenv来管理Ruby版本的方法_ruby专题

rbenv 用来管理多个版本的 ruby 在用户目录的安装和使用, 和 rvm 二选一使用. 具体区别 rbenv 的文档里有说明, 社区里也有讨论.系统需求 OSX: 请找一个网好的地方, 从 app store 里下载 xcode.app, 安装完成后运行, 在设置中的 Downloads 里安装 Command Line Tools. Linux: 请安装开发环境 (编译链接工具和 ruby 的依赖), 如果只要 jruby 有 jre 就可以了.安装 rbenv 在 osx 上可以直接用

使用C++来编写Ruby程序扩展的教程_ruby专题

Ruby 最酷的功能之一就是使用 C/C++ 定义的应用程序编程接口 (API) 扩展它.Ruby 提供了 C 头文件 ruby.h,它随附提供了许多功能,可使用这些功能创建 Ruby 类.模块和更多内容.除了头文件,Ruby 还提供了其他几个高层抽象来扩展基于本地 ruby.h 构建的 Ruby,本文要介绍的是 Ruby Interface for C++ Extensions 或 Rice.创建 Ruby 扩展 在进行任何 Ruby 的 C API 或 Rice 扩展前,我想明确地介绍一下创

Ruby中操作字符串的一些基本方法_ruby专题

 在Ruby中的String对象持有和操纵的任意序列的一个或多个字节,通常表示人类语言的字符表示. 简单的字符串文本括在单引号(单引号字符).引号内的文本的字符串值: 'This is a simple Ruby string literal' 如果需要内放置一个单引号,单引号的字符串文字,在它前面加上一个反斜杠Ruby解释器不认为终止字符串: 'Won\'t you read O\'Reilly\'s book?' 反斜杠也可以转义另一个反斜杠,这样第二个反斜杠本身不是解释为转义字符. 以下是

实例讲解Ruby使用设计模式中的装饰器模式的方法_ruby专题

概述       若你从事过面向对象开发,实现给一个类或对象增加行为,使用继承机制,这是所有面向对象语言的一  个基本特性.如果已经存在的一个类缺少某些方法,或者须要给方法添加更多的功能(魅力),你也许会仅仅继承这个类来产生一个新类-这建立在额外的代码上.       通过继承一个现有类可以使得子类在拥有自身方法的同时还拥有父类的方法.但是这种方法是静态的,用户不能控制增加行为的方式和时机.如果  你希望改变一个已经初始化的对象的行为,你怎么办?或者,你希望继承许多类的行为,改怎么办?前一个,只

Ruby程序中创建和解析XML文件的方法_ruby专题

使用builder创建XML builder安装方法: gem install builder require 'builder' x = Builder::XmlMarkup.new(:target => $stdout, :indent => 1) #":target =>$stdout"参数:指示输出内 容将被写向标准输出控制台 #":indent =>1"参数:XML输出形式将被缩 进一个空格字符x.instruct! :xml, :

举例讲解Ruby中require的使用方法_ruby专题

同一目录下的文件,如/usr/local/ruby/foo.rb与/usr/local/ruby/bar.rb两个文件. 如果直接在foo.rb中   require 'bar' 执行时会报找不到bar.rb错误. 这是因为运行   /home/oldsong$ ruby /usr/local/ruby/foo.rb 时会在ruby安装的lib目录和/home/oldsong/目录下查找bar.rb.而不会去rb文件的目录/usr/local/ruby/下查找. 所以除引用系统rb外,requi

在Ruby on Rails中优化ActiveRecord的方法_ruby专题

 Ruby on Rails 编程常常会将您宠坏.这一不断发展的框架会让您从其他框架的沉闷乏味中解脱出来.您可以用习以为常的几行代码片断表达自己的意图.而且还可以使用 ActiveRecord. 对于我这样的一个老 Java? 程序员而言,ActiveRecord 多少有点生疏.通过 Java 框架,我通常都会在独立的模型和模式之间构建一种映射.像这样的框架就是映射框架.通过 ActiveRecord,我只定义数据库模式:或者用 SQL 或者用称为迁移(migration)的 Ruby 类.将对

ruby 对象的初始化 方法_ruby专题

 前面一节的 Fruit 类有两个实变量,分别表述水果的类型和状态.直到为这个类写了一个定制的inspect方法,我们方才了解它不会对一个缺乏属性的水果做出合理的解释.幸运的是,Ruby提供了一种允许实变量总是被初始化的方法. initalize方法 当Ruby创建一个新对象时,它总是会寻找一个名为 initialize 的方法并执行它.因此,我们可以简单通过一个initialize方法向实变量中加入缺省值,这样一来, inspect方法就有东西可说了. ruby> class Fruit