迭代器的真实含义

简介: 迭代器的真实含义

迭代器”这个词多少有点误导性,这是因为迭代器并没有进行实际的迭代:真正的迭代是 for 循环完成的,迭代器只不过为每次的迭代提供连续的值。或许,称其为“生成器”更好,表示为迭代生成元素;不过,“迭代器”这个名字已经在诸如 Java 等其他语言中被广泛使用了。


然而,还有一种创建迭代器的方式可以让迭代器进行实际的迭代操作。当使用这种迭代器时,就不需要编写循环了。相反,只需要调用这个迭代器,并传入一个描述了在每次迭代时迭代器需要做什么的参数即可。更准确的说,迭代器接收了一个函数作为参数,这个函数在循环的内部被调用,这种迭代器就被称为真正的迭代器


如下所示:

function allwords(f)
  for line in io.lines() do
    for word in string.gmatch(line, "%w+") do
      f(word)
    end
  end
end


使用这个迭代器时,我们必须传入一个函数作为循环体。如果我们只想输出每个单词,那么简单地使用函数 print 即可:

allwords(print)


通常,我们可以使用一个匿名函数作为循环体。例如,以下的代码用于计算单词"hello"在输入文本中出现的次数:

local count = 0
allwords(function (w)
  if w == "hello" then count = count + 1 end
end)
print(count)


同样的需求,如果采用之前的迭代器风格,差异也不是特别大:

local count = 0
for w in allwords() do
  if w == "hello" then count = count + 1 end
end
print(count)


真正的迭代器在老版本的 Lua 语言中曾经非常流行,那是还没有 for 语句。


真正的迭代器与生成器风格的迭代器想比怎么样呢?这两种风格都有大致相同的开销,即每次迭代都有一次函数调用。一方面,编写真正的迭代器比较容易。另一方面,生成器风格的迭代器则更加灵活。首先,生成器风格的迭代器允许两个或更多个并行的迭代。其次,生成器风格的迭代器允许在循环体重使用 breakreturn 语句。使用真正的迭代器, return 语句从匿名函数中返回而并非从进行迭代的函数中返回。基于这些原因,高级 Lua 语言中一般更喜欢生成器风格的迭代器

目录
相关文章
|
8月前
|
算法 编译器 C语言
【C++ 迭代器的空类类型 】深入理解C++迭代器类别与空类标签的奥秘
【C++ 迭代器的空类类型 】深入理解C++迭代器类别与空类标签的奥秘
90 0
|
8月前
|
存储 数据可视化 C语言
C 语言数组教程:定义、访问、修改、循环遍历及多维数组解析
数组用于将多个值存储在单个变量中,而不是为每个值声明单独的变量。 要创建数组,请定义数据类型(例如 int)并指定数组名称,后面跟着方括号 []。 要将值插入其中,请使用逗号分隔的列表,并在花括号内使用
1144 0
|
8月前
|
存储 Java 索引
Java数组的地址值与元素访问技术
Java数组的地址值与元素访问技术
81 2
|
8月前
|
算法 数据处理 C语言
【C++迭代器深度解析】C++迭代器类型之间的继承关系与反向迭代器的独特性
【C++迭代器深度解析】C++迭代器类型之间的继承关系与反向迭代器的独特性
120 0
|
8月前
|
C++
stl判断数据的类型
stl判断数据的类型
|
编译器 C++ 容器
【STL】模拟实现反向迭代器
【STL】模拟实现反向迭代器
41 1
重生之我是孔乙己——查找数组缺失元素的几种方法
重生之我是孔乙己——查找数组缺失元素的几种方法
87 0
|
JavaScript API
伪数组转数组的几种方法
伪数组转数组的几种方法
140 0
|
JavaScript 索引
伪数组(类数组)
伪数组(类数组)
83 0
|
JavaScript
空值合并运算符真实使用场景及避坑
在 JS 里,我们要判断一个数值非空,常常需要运用下面的两个不等表达式进行判断,所以我一值有个疑惑,为什么不出一个同时判断不为 undefined 和 null 的方法
315 0