迭代器并不是Ruby发明
![](/icons/34152de.gif)
.它广泛地运用于各种面向对象语言.在Lisp中也有,只是不这么叫罢了.尽管如此,迭代器
![](/icons/34152de.gif)
概念并不为许多人熟悉,因此我们将在此做较为详细
![](/icons/34152de.gif)
介绍.
你知道,动词 iterate
![](/icons/34152de.gif)
意思是做同
![](/icons/34152yi.gif)
件事许多遍,因此,iterator就是用来将同
![](/icons/34152yi.gif)
件事做许多次
![](/icons/34152de.gif)
东西.
当我们写代码时,我们需要各种环境下
![](/icons/34152de.gif)
循环.在C里,我们用for或者while.比如,
char *str;
for (str = "abcdefg"; *str != '\0'; str
![](/icons/34152jiajia.gif)
) {
/* process a character here */
}
C
![](/icons/34152de.gif)
for(...)语法提供了
![](/icons/34152yi.gif)
种写循环
![](/icons/34152de.gif)
抽象思路方法,但测试 *str 是否为空(null)
![](/icons/34152zifu.gif)
需要
![](/icons/34152chengxu.gif)
员了解
![](/icons/34152zifu.gif)
串内部结构
![](/icons/34152de.gif)
细节.这让C看起来像低级(low-level)语言.更高级
![](/icons/34152de.gif)
语言是通过它们更具弹性
![](/icons/34152de.gif)
迭代器支持来实现
![](/icons/34152de.gif)
.考虑下面
![](/icons/34152de.gif)
sh 命令行脚本:
#!/bin/sh
for i in *.[ch]; do
# ... here would be something to do for each file
done
当前目录下所有
![](/icons/34152de.gif)
C源文件和头文件都将被处理,由命令行shell来
![](/icons/34152yi.gif)
个个地捡取文件名并处理其中
![](/icons/34152de.gif)
细节.我想这是在比 C 要高
![](/icons/34152de.gif)
级别上工作,你觉得呢?
但有更多值得我们考虑
![](/icons/34152de.gif)
:在
![](/icons/34152yi.gif)
种语言能够很好
![](/icons/34152de.gif)
给内建
![](/icons/34152de.gif)
数据类型
![](/icons/34152de.gif)
提供迭代器
![](/icons/34152de.gif)
同时,我们却仍需要回去用低级别
![](/icons/34152de.gif)
循环语言来实现对自己定义
![](/icons/34152de.gif)
数据类型
![](/icons/34152de.gif)
迭代,这真是让人失望.在面对对象编程时,用户经常
![](/icons/34152yi.gif)
个接
![](/icons/34152yi.gif)
个地定义数据类型,因此这是
![](/icons/34152yi.gif)
个很严重
![](/icons/34152de.gif)
问题.
因此,所有
![](/icons/34152de.gif)
OOP语言都包含了
![](/icons/34152yi.gif)
定
![](/icons/34152de.gif)
迭代器机制.某些语言为此提供
![](/icons/34152yi.gif)
种特殊
![](/icons/34152de.gif)
类;Ruby则允许我们直接定义迭代器.
Ruby
![](/icons/34152de.gif)
String类型有很多有用
![](/icons/34152de.gif)
迭代器:
ruby> "abc".each_
![](/icons/34152byte.gif)
{|c| pr
![](/icons/34152int.gif)
f "<%c>", c}; pr
![](/icons/34152int.gif)
"\n"
<a><b><c>
nil
each_
![](/icons/34152byte.gif)
是个用于
![](/icons/34152zifu.gif)
串中每个
![](/icons/34152zifu.gif)
![](/icons/34152de.gif)
迭代器.每个
![](/icons/34152zifu.gif)
串由局部变量c代替.这可以翻译为类似C
![](/icons/34152de.gif)
代码...
ruby> s="abc";i=0
0
ruby> while i<s.length
| pr
![](/icons/34152int.gif)
f "<%c>", s[i]; i
![](/icons/34152jiadeng.gif)
1
| end; pr
![](/icons/34152int.gif)
"\n"
<a><b><c>
nil
...然而, each_
![](/icons/34152byte.gif)
迭代器在概念上要简单些,而且即使以后 String 类突然有所改变也应该可以照样工作.使用迭代器
![](/icons/34152de.gif)
![](/icons/34152yi.gif)
个好处便是在此类改变中仍然可以保持健壮;
![](/icons/34152yi.gif)
般
![](/icons/34152de.gif)
,它
![](/icons/34152de.gif)
确是好代码
![](/icons/34152de.gif)
![](/icons/34152yi.gif)
个特点.(好,请有点儿耐心,我们将会马上谈到什么是类)
String
![](/icons/34152de.gif)
另
![](/icons/34152yi.gif)
个迭代器是 each_line.
ruby> "a\nb\nc\n".each_line{|l| pr
![](/icons/34152int.gif)
l}
a
c
nil
采用迭代器,这将很轻松
![](/icons/34152de.gif)
取代C
![](/icons/34152de.gif)
大多数编程效果(找换行符,生成子串等等)
前面出现
![](/icons/34152de.gif)
for语句通过each迭代器实现迭代功能. String
![](/icons/34152de.gif)
each和each_line
![](/icons/34152de.gif)
工作原理差不多,让我们用for重写上面
![](/icons/34152de.gif)
例子:
ruby> for l in "a\nb\nc\n"
| pr
![](/icons/34152int.gif)
l
| end
a
c
nil
我们可以用retry流程控制语句连接迭代循环,它会从头执行当前循环
![](/icons/34152de.gif)
迭代.
ruby> c=0
0
ruby> for i in 0..4
| pr
![](/icons/34152int.gif)
i
|
![](/icons/34152if.gif)
i
![](/icons/34152dd.gif)
2 and c
![](/icons/34152dd.gif)
0
| c = 1
| pr
![](/icons/34152int.gif)
"\n"
| retry
| end
| end; pr
![](/icons/34152int.gif)
"\n"
012
01234
nil
yield有时会在
![](/icons/34152yi.gif)
个迭代器
![](/icons/34152de.gif)
定义中出现. yield将流程控制移至传递给迭代器
![](/icons/34152de.gif)
代码域(这将会在过程对象那
![](/icons/34152yi.gif)
节介绍更多
![](/icons/34152de.gif)
细节).下面
![](/icons/34152de.gif)
例子定义了
![](/icons/34152yi.gif)
个repeat迭代器,会依参数
![](/icons/34152de.gif)
设置执行多次代码域.
ruby> def repeat(num)
| while num > 0
| yield
| num -= 1
| end
| end
nil
ruby> repeat(3) { pr
![](/icons/34152int.gif)
"foo\n" }
foo
foo
foo
nil
利用retry,我们可以定义
![](/icons/34152yi.gif)
个有while相同作用
![](/icons/34152de.gif)
迭代器,虽然在实际应用中它太慢了.
ruby> def WHILE(cond)
|
![](/icons/34152if.gif)
not cond
| yield
| retry
| end
nil
ruby> i=0; WHILE(i<3) { pr
![](/icons/34152int.gif)
i; i
![](/icons/34152jiadeng.gif)
1 }
012 nil
搞懂什么是迭代器了吗?有
![](/icons/34152yi.gif)
些限制,但你可以写自己
![](/icons/34152de.gif)
迭代器;实际上,当你定义
![](/icons/34152yi.gif)
个新
![](/icons/34152de.gif)
数据类型时,为它定义
![](/icons/34152yi.gif)
个合适
![](/icons/34152de.gif)
迭代器经常也很方便.这样看来,上面
![](/icons/34152de.gif)
例子并不是很好用.在我们理解了类以后,我们可以讨论讨论更具实际意义
![](/icons/34152de.gif)
迭代器.
延伸阅读
最新评论