搜索
查看: 5594|回复: 11

[入门教程] 理解迭代器

  [复制链接]

30

主题

695

帖子

4178

积分

超级版主

Rank: 8Rank: 8

积分
4178
发表于 2015-12-3 18:47:39 | 显示全部楼层 |阅读模式
一、最简单的例子

首先我们把迭代器的一大堆复杂的语法描述先扔到一边,看来一个简单至极的使用迭代器的示例:

import console;

//each函数创建一个迭代器
each = function(){
   
   
//在局部变量闭包中保存一些需要用到的数据
    var i = 0;
   
   
//下面返回一个迭代器 - 实际上就是一个函数。
    return function(){
        i++;
        
if( i < 10 ) return i; //迭代器函数会被循环调用,直到他返回的是空值
    }
}

for( i in each() ){
    console.log(
"i",i)
}

console.pause(
true);
从上面我的代码我们了解到:
1、迭代器实际上就是一个函数对象,这个函数会在for语句中被多次的循环调用
2、each函数是用来创建迭代器的,这个创建迭代器的函数我们称之为“迭代器生成器”,for语句在开始循环以前会调用each函数并获取迭代器函数。


参考aardio帮助文档:《泛型for与迭代器》


评分

参与人数 1银币 +10 收起 理由
liubing19860405 + 10 赞一个!

查看全部评分

回复

使用道具 举报

30

主题

695

帖子

4178

积分

超级版主

Rank: 8Rank: 8

积分
4178
 楼主| 发表于 2015-12-3 19:21:17 | 显示全部楼层

二、为迭代器生成器添加参数




上面一节给出的例子返回的迭代器返回了0到10中间的整数,
现在我们希望生成器一些参数让他生产不同的迭代器,例如我们可以指定数值从哪里开始、到哪里结束。


示例:
import console;

//each函数创建一个迭代器
each = function(min,max){
   
   
//下面返回一个迭代器  
    return function(){
        min++;
        
if( min <= max ) return min-1;
    }
}

for( i in each(10,20) ){
    console.log(
"i",i)
}

console.pause(
true);


回复

使用道具 举报

30

主题

695

帖子

4178

积分

超级版主

Rank: 8Rank: 8

积分
4178
 楼主| 发表于 2015-12-3 19:27:47 | 显示全部楼层

三、使用一个集合对象作为参数


现在我们又有了新的需求,我们不是要求迭代器循环列出min到max之间的数值。
而是希望给迭代器一个集合对象,要求迭代器根据一定的规则列出我们需要的成员。

那么我们进一目改进迭代器如下:
import console;

//each函数创建一个迭代器
each = function( array ){
     
   
var i = 0;
   
return function(){
        i++;
        
if( array[ i ] ) return array[ i ];  
    }
}

var arr = {1;23;45};
for( n in each( arr ) ){
    console.log(
"n",n)
}

console.pause(
true);


回复

使用道具 举报

30

主题

695

帖子

4178

积分

超级版主

Rank: 8Rank: 8

积分
4178
 楼主| 发表于 2015-12-3 19:45:24 | 显示全部楼层

四、使用 owner 传递集合对象参数


通过学习aardio基础语法,我们知道在调用一个对象的成员函数时 - 函数默认会提供owner参数指向他所在的集合。
所以如果我们把上面的 each( array ) = function(){}  函数修改为 arr.each = function(){}  以后,就可以在迭代器内部使用owner对象来访问集合对象了。

我们想当然的把上一节的代码修改如下:
import console;

var arr = {1;23;45};
arr.each =
function(){
     
   
var i = 0;
   
return function(){
        i++;
      
if( owner[ i ] ) return owner[ i ];  
    }
}

for n in arr.each() {
    console.log(
"n",n)
}

console.pause(
true);

可是运行后,代码报错了,说是 onwer参数为null,出错行为上面红字标出的那行。

我们知道每个函数都有自己的owner参数,arr.each函数内部的owner参数无疑就是指向arr对象。
但在 arr.each 内部创建的新函数( 也就是那个迭代器 )并不是任何集合对象的成员,他的owner对象是空的。
关于owner参数的详细说明,请参考这里:owner参数

这该如何是好呢?!
幸运的是 - aardio中提供了一种机制,for语句可以在接受迭代器生成器的多个返回值,你可以用第一个返回值返回迭代器,你可以用第二个返回值返回迭代器的owner对象,正确的代码如下:
import console;

var arr = {1;23;45};
arr.each =
function(){
     
   
var i = 0;
   
return function(){
        i++;
        
if( owner[ i ] ) return owner[ i ];  
    },
owner //使用第二个返回值显式指定迭代器的owner参数
}

for n in arr.each() {
    console.log(
"n",n)
}

console.pause(
true);

如果上面的代码让你困惑,这也没关系,只要不使用owner这个特殊的名字,你完全可以简单而粗暴的把代码写成下面这样:
import console;

var arr = {1;23;45};
arr.each =
function(){
     
   
var i = 0;
   
var 集合对象 = owner;
   
return function(){
        i++;
        
if( 集合对象[ i ] ) return 集合对象[ i ];  
    }
}

for n in arr.each() {
    console.log(
"n",n)
}

console.pause(
true);

回复

使用道具 举报

30

主题

695

帖子

4178

积分

超级版主

Rank: 8Rank: 8

积分
4178
 楼主| 发表于 2015-12-3 20:05:40 | 显示全部楼层

五、无状态迭代器、有状态迭代器


var arr = {1;23;45};
arr.each =
function(){
     
   
var i = 0;
   
var 集合对象 = owner;
   
return function(){
        i++;
        
if( 集合对象[ i ] ) return 集合对象[ i ];  
    }
}

上面一个范例把集合对象保存在了迭代器生成器函数创建的局部变量的闭包中,这种使用上层生成器函数的局部变量保存迭代器所需的集合对象以及状态的迭代器,我们称之为“有状态的迭代器”。

而依赖for语句来传递迭代器集合对象、以及状态值的叫“无状态的迭代器”,也就是说这种迭代器依赖for语句来保持状态。
我们前面说过了,for语句在循环开始首先调用迭代器生成器,迭代器生成器可以返回以下三个返回值。
迭代器,集合对象,控制变量 = 迭代器生成器( 可选的生成器参数 )
当然集合对象,控制变量这两个返回值都是可选的,
如果迭代器生成器返回了集合对象,那么for语句会在每次调用迭代器时把他指定为迭代器的owner参数。
如果返回了控制变量,for语句会在调用迭代器时把控制变量作为调用参数传过去,而每次调用迭代器的第一个返回值会成为新的控制变量的值。

听起来是不是很复杂?!其实我们一般用不上这种写法,但我们还是来看一个简单的例子:
import console;

var each = function(集合对象){
      
   
return function(控制变量){
   
        控制变量++;
        
if( owner[控制变量] ) return 控制变量/*新的值*/,集合对象[控制变量];
         
    },集合对象,0
/*控制变量的初始值*/
}

var arr = {1;23;45};
for i,v in each(arr) {
    console.log(i,v)
}

console.pause(
true);
上面就是一个无状态的迭代器,其实就是一个语法糖,利用for语句来传递一些迭代器的状态而已。


实际应用中,不必去区分一个迭代器是有状态还是无状态,两种方法可以混合起来使用。
回复

使用道具 举报

30

主题

695

帖子

4178

积分

超级版主

Rank: 8Rank: 8

积分
4178
 楼主| 发表于 2015-12-3 20:25:36 | 显示全部楼层

六、那些each函数


在aardio中有一个规则,所有对象提供的迭代器生成器的函数名都以"each"开始,例如:
import console;

import process;
for processEntry in process.each( ".*.exe" ) {  
    console.log( processEntry.szExeFile )
}

import winex;
for hwnd,title,theadId,processId in winex.each() {  
    console.log( hwnd,title,theadId,processId  )
}
console.pause(
true);
所以,请善用aardio编辑器提供的智能提示找到您需要的迭代器生成器:
each.png

回复

使用道具 举报

30

主题

695

帖子

4178

积分

超级版主

Rank: 8Rank: 8

积分
4178
 楼主| 发表于 2015-12-3 21:47:45 | 显示全部楼层

七、使用协程生成器创建迭代器

import console;

function fib(max){
   
var a, b = 1, 1;
   
while a < max {
        fiber.yield( a );
        a, b = b, a+b;
    }
}

for v in fiber.generator(fib,console.getNumber( "请输入斐波那契数列范围:" )) {
    console.log( v )   
}

console.pause()
  


回复

使用道具 举报

2

主题

13

帖子

94

积分

一级会员

Rank: 2

积分
94
发表于 2016-1-19 22:44:01 | 显示全部楼层

祝aardio越来越好!!!!

祝aardio越来越好!!!!
回复

使用道具 举报

0

主题

30

帖子

204

积分

二级会员

Rank: 3Rank: 3

积分
204
发表于 2016-2-4 19:19:27 | 显示全部楼层

教程越来越多啦

教程越来越多啦
回复

使用道具 举报

0

主题

8

帖子

49

积分

培训班

积分
49
发表于 2016-9-9 22:29:04 | 显示全部楼层

不错呀,新手来学习一下

不错呀,新手来学习一下
回复

使用道具 举报

11

主题

51

帖子

369

积分

新手入门

积分
369
发表于 2017-3-5 20:39:21 | 显示全部楼层
不错,学习了
回复

使用道具 举报

0

主题

21

帖子

119

积分

一级会员

Rank: 2

积分
119
发表于 2017-5-28 04:55:20 | 显示全部楼层
aardio不愧是一种动静皆宜的语言,迭代器就体现了aardio可以把一个函数作为一种数据类型来进行传递和调用
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册会员

本版积分规则

手机版|未经许可严禁引用或转载本站文章|站长邮箱|aardio.com|aardio官方社区 ( 皖ICP备09012014号 )

GMT+8, 2018-11-15 19:12 , Processed in 0.093754 second(s), 26 queries .

Powered by Discuz! X3.4

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表