先代表,我是个正在学习 Lua 的新手,在遇到些学习上的问题,通过思考尝试,让后写下我对相关问题知识的认识。
个人博客:https://crabsaberv.github.io/html
从菜鸟教程上学习 Lua 迭代器过程当中,遇到了些障碍。虽然根据菜鸟教程中的解释:git
下面咱们看看泛型 for 的执行过程:github
- 首先,初始化,计算 in 后面表达式的值,表达式应该返回泛型 for 须要的三个值:迭代函数、状态常量、控制变量;与多值赋值同样,若是表达式返回的结果个数不足三个会自动用 nil 补足,多出部分会被忽略。
- 第二,将状态常量和控制变量做为参数调用迭代函数(注意:对于 for 结构来讲,状态常量没有用处,仅仅在初始化时获取他的值并传递给迭代函数)。
- 第三,将迭代函数返回的值赋给变量列表。
- 第四,若是返回的第一个值为nil循环结束,不然执行循环体。
- 第五,回到第二步再次调用迭代函数
可是在本身更具理解,试着编写一些测试 Lua 无状态迭代器代码时,出现的结果却让人捉急。
可先阅览 Lua 官方文档中对迭代器的描述: Lua 5.3 文档 -3.3.5
(能看懂官方解释,基本上本文就没必要往下看了)shell
开始根据菜鸟教程编写了一个无状态迭代器,固然运行结果也正常。闭包
function square(iteratorMaxCount,currerntNumber) if currerntNumber < iteratorMaxCount then currerntNumber = currerntNumber+1; return currerntNumber,currerntNumber*currerntNumber; end end for i,n in square,10,0 do print(i,n) end
这段代码的行为其实很简单,就是打印了10之内全部的平方数。
根据菜鸟教程描述的 for 的执行过程可知,suqare 就是迭代器函数,10是状态常量,0则是控制变量。而当运行时,会先根据 square 以及参数,获得迭代器的三个元素(迭代函数,状态常量,控制变量),之后就会利用这三个元素来进行迭代的过程。函数
但这里菜鸟教程对这里有些轻描淡写,并没说清楚真正各个参数是如何被使用,尤为是 square 的参数和返回值之间的联系或者是否有联系,却没讲清楚。学习
后来,我在想常常性在 for 中用两个变量来接收,能不能只用一个 临时变量来接收迭代结果,而且迭代器函数可否只有一个参数,一个返回值。测试
因而有了下面的代码:ui
function aa(a) if a<10 then a = a+1 return a end end for i in aa,1 do print(i) end
以我最初对迭代器的理解,应该会执行10次运算,然而:lua
2 2 2 . . .
无限循环打印 2 。
此时就开始纳闷了,这个迭代器的内部原理到底是什么,aa() 被作了,其中的参数 a 又作了什么处理,返回的 a 除了赋值给了 i,而后又去了哪里。
为了解决这些疑问,我尝试了不少种不一样的组合形式,好比将参数设置为2个,返回值设置成多个,参数调换位置等,但不少时候最后的表现结果却和预期差的很远。
没有办法,百度不给力,那就只能去看 Lua 的官方文档了。
果不其然,官方的解释很是好理解,还给了示例。
参照官方文档-3.3.5的解释:
for statement like
for var_1, ···, var_n in explist do block end
is equivalent to the code:
do local f, s, var = explist while true do local var_1, ···, var_n = f(s, var) var = var_1 if var == nil then break end block end end
上面的迭代器遍历能够看做是下面的过程:
可见一开始由 do 语句块将包裹起来,其中会建立三个变量,而这三个变量 f,s,var 正好对应着迭代器三元素:f-迭代器函数,s-状态常量,var-控制变量。其值由 explist 的返回值得到。这也就证实了为什么 for 迭代器 in 后面的最终函数必须以:“迭代器函数,状态常量,控制变量“ 的形式/结构来编写。
后来在语句块中编写一个 while 循环,其内部又用多个局部变量 var_x,来接收 f(s,var) 的结果。而能看出这些 var_x 就是咱们 for 循环中用于接收迭代过程结果的变量。这就构成了一个闭包,f 就是这里的一个闭包函数。
而下面的语句,将 var_1 接收到的 var 的值又再次赋值给 var。var 是一个外部变量,那么在下次循环中,f(s,var)
的 var 传入的就是新值,也便是控制变量的更新。
当 var 为 nil 时,循环就会跳出。
参考了这些,我认为对于无状态迭代器的编写须要遵照几个规则:
参照这几个规则,基本上能保证咱们编写的无状态迭代器不会出现什么超出预期的问题。
而根据分析,也能得出关于迭代器的内部参数特色: