【背景】
泛型 for 在自己内部保存迭代函数,实际上它保存三个值:迭代函数、状态常量、控制变量。
下面我们看看泛型 for 的执行过程:
1.首先,初始化,计算 in 后面表达式的值,表达式应该返回泛型 for 需要的三个值:迭代函数、状态常量、控制变量;与多值赋值一样,如果表达式返回的结果个数不足三个会自动用 nil 补足,多出部分会被忽略。
2.第二,将状态常量和控制变量作为参数调用迭代函数(注意:对于 for 结构来说,状态常量没有用处,仅仅在初始化时获取他的值并传递给迭代函数)。
3.第三,将迭代函数返回的值赋给变量列表。(k, v为变量列表)
4.第四,如果返回的第一个值为nil循环结束,否则执行循环体。
5.第五,回到第二步再次调用迭代函数
在Lua中我们常常使用函数来描述迭代器,每次调用该函数就返回集合的下一个元素。Lua 的迭代器包含以下两种类型:
1.无状态的迭代器
2.多状态的迭代器
迭代器的状态包括被遍历的表(循环过程中不会改变的状态常量)和当前的索引下标(控制变量),ipairs 和迭代函数都很简单,我们在 Lua 中可以这样实现:
function iter (a, i)
i = i + 1
local v = a[i]
if v then --“if v”的意思是“当v为nil或false时该条件语句的判断为false,不执行分支语句”,但事实上,v可以为false,虽然当v为false时并不满足if v 这个条件——看附录。
return i, v
end
end
function ipairs (a)
return iter, a, 0
end
当 Lua 调用 ipairs(a) 开始循环时,他获取三个值:迭代函数 iter、状态常量 a、控制变量初始值 0;然后 Lua 调用 iter(a,0) 返回 1, a[1](除非 a[1]=nil);第二次迭代调用 iter(a,1) 返回 2, a[2]……直到第一个 nil 元素。
【正文】
关于泛型for循环,有两个需要注意的问题。
如果仔细思考,可以发现这两个问题都已经被我标注出来了,就是上方的粗体斜体字。
这两个问题是:
1.到底怎么样才会让for退出?
2.什么叫“每次调用该函数就返回集合的下一个元素”
这篇文章说第一个,用户到底要做什么才能退出泛型for循环。
先看下列代码
> a = {} --成功,不报错
> a['s'] = 12 --成功,不报错
> a[2] = 3 --成功,不报错
> a[a] = 2 --成功,不报错
> a[foo] = 56 -- table index is nil
于是我们得到第一个结论:lua并不支持用户将nil类型的值作为key使用
再看下列代码
> a = {1,2,3,4,nil,'tyt','rrp',nil,20,30,'xss'}
> for k,v in ipairs(a) do
>> print(k,v)
>> end
1 1
2 2
3 3
4 4
> for k,v in pairs(a) do
>> print(k,v)
>> end
1 1
2 2
3 3
4 4
6 tyt
7 rrp
9 20
10 30
11 xss
在这里,lua直接跳过为value为nil的键值对,但并没有报错;不仅没报错,甚至还为这些值为nil的键值对计算了key,导致key出现断层。
于是我们可以得到第二个结论:lua支持nil作为表的value
所以可见,更有可能是当key为nil时退出for循环,而不是当value为nil时退出(即所谓的“a[1]=nil”“直到第一个nil元素”)
下面来证实一下这个说法。
a = {1,2,3,4,5,6,7}
function iter (a, i)
i = i + 1
local v = a[i]
if v then
return i, nil
end
end
function ipairs (a)
return iter, a, 0
end
for k,v in ipairs(a) do
print(k,v)
end
输出
1 nil
2 nil
3 nil
4 nil
5 nil
6 nil
7 nil
对比对照
a = {1,2,3,4,5,6,7}
function iter (a, i)
i = i + 1
local v = a[i]
if v then
return nil,v
end
end
function ipairs (a)
return iter, a, 0
end
for k,v in ipairs(a) do
print(k,v)
end
输出
--无
综上,当迭代器给value返回了一个nil值时,for循环继续运行;当迭代器给key返回了一个nil值时,for循环退出
那么正常的ipairs是怎么工作的呢?
for循环写好后,lua会优先计算右边表达式的值:ipairs返回给for三个信息,iter函数、要被迭代的对象(状态常量)、下标(控制变量)。之后,for开始执行iter函数。
iter函数执行中,当lua处理到分支语句时
1.如果v为nil则条件判断为false,那么就不执行return语句,因此i的值就未被返回到k上去,结果k的值被设为nil,所以跳出循环。(有两种不同的操作可以使k为nil,大概的原理见延伸2)
2.如果v不是nil,也就是说v有具体的值,那么执行return语句。因为i一定是一个number类变量,所以for会一直执行、循环,直到v为nil时
延伸:
1.要想for运行,那么迭代器返回的第一个元素就至关重要——第二个、第三个、第n个元素都是可有可无的,但第一个元素必定不能为nil
2.在for循环体内更改k、v的值并不能造成for循环退出。根据lua手册的解释
“环变量 var_i 对于循环来说是一个局部变量; 你不可以在 for 循环结束后继续使用。 如果你需要保留这些值,那么就在循环跳出或结束前赋值到别的变量里去”
我认为每进行一次循环,都相当于做了一次“local k,v = iter(状态常量,控制变量)”的操作。在这个操作中,lua已经做完了对于k是否为nil值这个问题的检测操作——这是lua自动进行的,是和for关键字绑定在一起的,所以在循环体内更改k、v并没有什么影响。
也因此,当iter没有返回值时,k会变成nil,具体的原理见延伸4.
3.如何证明每次循环都会新建同名本地变量
原理:在同一作用域中,使用local关键字定义同名变量时,lua不会将原有变量设为nil——也就是说原有变量会保留其原来的值,不会变成新定义时赋予的值,也不会变为nil——但此时该原有变量已无法手动访问,除非闭包。而如果该原有变量没有外部引用来为它形成闭包的话,它会被回收。
collectgarbage("stop")
for k,v in ipairs({1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9}) do
k = {1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,91,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8}
v = {1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,91,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8}
print(collectgarbage("count"))
end
for k,v in ipairs({1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9}) do
k = {1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,91,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8}
v = {1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,91,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8}
print(collectgarbage("count"))
end
for k,v in ipairs({1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9}) do
k = {1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,91,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8}
v = {1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,91,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8}
print(collectgarbage("count"))
end
for k,v in ipairs({1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9}) do
k = {1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,91,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8}
v = {1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,91,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8}
print(collectgarbage("count"))
end
for k,v in ipairs({1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9}) do
k = {1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,91,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8}
v = {1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,91,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8}
print(collectgarbage("count"))
end
for k,v in ipairs({1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9}) do
k = {1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,91,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8}
v = {1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,91,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8}
print(collectgarbage("count"))
end
for k,v in ipairs({1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9}) do
k = {1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,91,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8}
v = {1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,91,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8}
print(collectgarbage("count"))
end
for k,v in ipairs({1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9}) do
k = {1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,91,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8}
v = {1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,91,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8}
print(collectgarbage("count"))
end
collectgarbage("collect")
for k,v in ipairs({1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9}) do
k=nil
v=nil
print(collectgarbage("count"))
end
for k,v in ipairs({1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9}) do
k=nil
v=nil
print(collectgarbage("count"))
end
for k,v in ipairs({1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9}) do
k=nil
v=nil
print(collectgarbage("count"))
end
for k,v in ipairs({1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9}) do
k=nil
v=nil
print(collectgarbage("count"))
end
for k,v in ipairs({1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9}) do
k=nil
v=nil
print(collectgarbage("count"))
end
for k,v in ipairs({1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9}) do
k=nil
v=nil
print(collectgarbage("count"))
end
for k,v in ipairs({1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9}) do
k=nil
v=nil
print(collectgarbage("count"))
end
for k,v in ipairs({1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9}) do
k=nil
v=nil
print(collectgarbage("count"))
end
--[[
>lua -e "io.stdout:setvbuf 'no'" "定义全局变量和local定义变量肯定不是幂等的.lua"
41.6533203125
43.9951171875
46.3369140625
48.6787109375
51.0205078125
53.3623046875
55.7041015625
58.0458984375
60.3876953125
62.7294921875
65.0712890625
67.4130859375
69.7548828125
72.0966796875
74.4384765625
76.7802734375
79.1220703125
81.4638671875
83.8056640625
86.1474609375
88.4892578125
90.8310546875
93.1728515625
95.5146484375
97.8564453125
100.1982421875
102.541015625
104.8828125
107.22265625
109.5634765625
111.90625
114.244140625
116.5859375
118.92578125
121.2666015625
123.609375
126.5419921875
128.884765625
131.2265625
133.56640625
135.9072265625
138.25
140.5849609375
142.927734375
145.26953125
148.6103515625
150.953125
153.2919921875
155.634765625
157.9765625
160.31640625
162.6572265625
165
167.33203125
169.6728515625
172.015625
174.3544921875
176.697265625
179.0390625
181.37890625
183.7197265625
186.0625
188.3994140625
190.7421875
193.08203125
195.4228515625
197.765625
200.1044921875
202.447265625
204.7890625
207.12890625
209.4697265625
212.40625
214.744140625
217.0859375
219.42578125
221.7666015625
224.109375
226.4482421875
228.791015625
231.1328125
233.47265625
235.8134765625
238.15625
240.494140625
242.8359375
245.17578125
247.5166015625
249.859375
252.1982421875
254.541015625
256.8828125
259.22265625
261.5634765625
263.90625
266.244140625
268.5859375
270.92578125
273.2666015625
275.609375
277.9482421875
280.291015625
282.6328125
284.97265625
287.3134765625
289.65625
291.994140625
294.3359375
297.26953125
299.6103515625
301.953125
304.2919921875
306.634765625
308.9765625
311.31640625
313.6572265625
316
318.33203125
320.6728515625
323.015625
325.3544921875
327.697265625
330.0390625
332.37890625
334.7197265625
337.0625
339.3994140625
341.7421875
344.08203125
346.4228515625
348.765625
351.1044921875
353.447265625
355.7890625
358.12890625
360.4697265625
362.8125
365.1494140625
367.4921875
369.83203125
372.1728515625
374.515625
376.8544921875
379.197265625
382.1328125
384.47265625
386.8134765625
389.15625
391.494140625
393.8359375
396.17578125
398.5166015625
400.859375
403.1982421875
405.541015625
407.8828125
410.22265625
412.5634765625
414.90625
417.244140625
419.5859375
421.92578125
424.2666015625
426.609375
428.9482421875
431.291015625
433.6328125
435.97265625
438.3134765625
440.65625
442.994140625
445.3359375
447.67578125
450.0166015625
452.359375
454.6982421875
457.041015625
459.3828125
461.72265625
464.0634765625
467
469.33203125
471.6728515625
474.015625
476.3544921875
478.697265625
481.0390625
483.37890625
485.7197265625
488.0625
490.3994140625
492.7421875
495.08203125
497.4228515625
499.765625
502.1044921875
504.447265625
506.7890625
509.12890625
511.4697265625
513.8125
516.1494140625
518.4921875
520.83203125
523.1728515625
525.515625
527.8544921875
530.197265625
532.5390625
534.87890625
537.2197265625
539.5625
541.8994140625
544.2421875
546.58203125
548.9228515625
551.859375
554.1982421875
556.541015625
558.8828125
561.22265625
563.5634765625
565.90625
568.244140625
570.5859375
572.92578125
575.2666015625
577.609375
579.9482421875
582.291015625
584.6328125
586.97265625
589.3134765625
591.65625
593.994140625
596.3359375
598.67578125
601.0166015625
603.359375
605.6982421875
608.041015625
610.3828125
612.72265625
615.0634765625
617.40625
619.744140625
622.0859375
624.42578125
626.7666015625
629.109375
631.4482421875
633.791015625
636.7265625
639.06640625
641.4072265625
643.75
646.0849609375
648.427734375
650.76953125
653.1103515625
655.453125
657.7919921875
660.134765625
662.4765625
664.81640625
667.1572265625
669.5
671.833984375
674.17578125
676.5166015625
678.859375
681.1982421875
683.541015625
685.8828125
688.22265625
690.5634765625
692.90625
695.244140625
697.5859375
699.92578125
702.2666015625
704.609375
706.9482421875
709.291015625
711.6328125
713.97265625
716.3134765625
718.65625
38.1357421875
38.1650390625
38.1943359375
38.2236328125
38.2529296875
38.2822265625
38.3115234375
38.3408203125
38.3701171875
38.3994140625
38.4287109375
38.4580078125
38.4873046875
38.5166015625
38.5458984375
38.5751953125
38.6044921875
38.6337890625
38.6630859375
38.6923828125
38.7216796875
38.7509765625
38.7802734375
38.8095703125
38.8388671875
38.8681640625
38.8974609375
38.9267578125
38.9560546875
38.9853515625
39.0146484375
39.0439453125
39.0732421875
39.1025390625
39.1318359375
39.1611328125
39.7841796875
39.8134765625
39.8427734375
39.8720703125
39.9013671875
39.9306640625
39.9599609375
39.9892578125
40.0185546875
40.0478515625
40.0771484375
40.1064453125
40.1357421875
40.1650390625
40.1943359375
40.2236328125
40.2529296875
40.2822265625
40.3115234375
40.3408203125
40.3701171875
40.3994140625
40.4287109375
40.4580078125
40.4873046875
40.5166015625
40.5458984375
40.5751953125
40.6044921875
40.6337890625
40.6630859375
40.6923828125
40.7216796875
40.7509765625
40.7802734375
40.8095703125
41.4326171875
41.4619140625
41.4912109375
41.5205078125
41.5498046875
41.5791015625
41.6083984375
41.6376953125
41.6669921875
41.6962890625
41.7255859375
41.7548828125
41.7841796875
41.8134765625
41.8427734375
41.8720703125
41.9013671875
41.9306640625
41.9599609375
41.9892578125
42.0185546875
42.0478515625
42.0771484375
42.1064453125
42.1357421875
42.1650390625
42.1943359375
42.2236328125
42.2529296875
42.2822265625
42.3115234375
42.3408203125
42.3701171875
42.3994140625
42.4287109375
42.4580078125
43.0810546875
43.1103515625
43.1396484375
43.1689453125
43.1982421875
43.2275390625
43.2568359375
43.2861328125
43.3154296875
43.3447265625
43.3740234375
43.4033203125
43.4326171875
43.4619140625
43.4912109375
43.5205078125
43.5498046875
43.5791015625
43.6083984375
43.6376953125
43.6669921875
43.6962890625
43.7255859375
43.7548828125
43.7841796875
43.8134765625
43.8427734375
43.8720703125
43.9013671875
43.9306640625
43.9599609375
43.9892578125
44.0185546875
44.0478515625
44.0771484375
44.1064453125
44.7294921875
44.7587890625
44.7880859375
44.8173828125
44.8466796875
44.8759765625
44.9052734375
44.9345703125
44.9638671875
44.9931640625
45.0224609375
45.0517578125
45.0810546875
45.1103515625
45.1396484375
45.1689453125
45.1982421875
45.2275390625
45.2568359375
45.2861328125
45.3154296875
45.3447265625
45.3740234375
45.4033203125
45.4326171875
45.4619140625
45.4912109375
45.5205078125
45.5498046875
45.5791015625
45.6083984375
45.6376953125
45.6669921875
45.6962890625
45.7255859375
45.7548828125
46.3779296875
46.4072265625
46.4365234375
46.4658203125
46.4951171875
46.5244140625
46.5537109375
46.5830078125
46.6123046875
46.6416015625
46.6708984375
46.7001953125
46.7294921875
46.7587890625
46.7880859375
46.8173828125
46.8466796875
46.8759765625
46.9052734375
46.9345703125
46.9638671875
46.9931640625
47.0224609375
47.0517578125
47.0810546875
47.1103515625
47.1396484375
47.1689453125
47.1982421875
47.2275390625
47.2568359375
47.2861328125
47.3154296875
47.3447265625
47.3740234375
47.4033203125
48.0263671875
48.0556640625
48.0849609375
48.1142578125
48.1435546875
48.1728515625
48.2021484375
48.2314453125
48.2607421875
48.2900390625
48.3193359375
48.3486328125
48.3779296875
48.4072265625
48.4365234375
48.4658203125
48.4951171875
48.5244140625
48.5537109375
48.5830078125
48.6123046875
48.6416015625
48.6708984375
48.7001953125
48.7294921875
48.7587890625
48.7880859375
48.8173828125
48.8466796875
48.8759765625
48.9052734375
48.9345703125
48.9638671875
48.9931640625
49.0224609375
49.0517578125
49.6748046875
49.7041015625
49.7333984375
49.7626953125
49.7919921875
49.8212890625
49.8505859375
49.8798828125
49.9091796875
49.9384765625
49.9677734375
49.9970703125
50.0263671875
50.0556640625
50.0849609375
50.1142578125
50.1435546875
50.1728515625
50.2021484375
50.2314453125
50.2607421875
50.2900390625
50.3193359375
50.3486328125
50.3779296875
50.4072265625
50.4365234375
50.4658203125
50.4951171875
50.5244140625
50.5537109375
50.5830078125
50.6123046875
50.6416015625
50.6708984375
50.7001953125
>Exit code: 0
]]--
4.为什么没有返回值时k会是nil?换句话说,要怎么样才能让上个循环中变量的信息不会保留到下一个循环中去?
for循环对于其局部变量k、v的定义可能等价于“local k,v = iter(状态常量,控制变量)”,也可能等价于“local k;local v;k,v = iter(状态常量,控制变量)”。这两种写法最终得到的结果是一样的,但其中有一些值得关注的细节。
local x会强制创造一个叫做x的nil值。
第一种写法直接让k、v等于iter的返回值,第二种写法则是先为它们赋值为nil再分配返回值。
(当然,这两种写法也有其他的区别。lua在发现一个函数类型的变量时,会先找局部变量再找全局变量。这种写法上的差异会造成递归bug。)
而对于“接受返回值”这个行为,看下列代码
> function f()
>> end
> x = f()
> print(x)
nil
> print(f())
--空
> y = 12
> y = f()
> print(y)
nil
>
> function f()
>> return nil
>> end
> print(f())
nil
>
看起来这是一个奇怪的bug,print可以打印x(nil值),却无法打印f()(不返回任何值),但我们也可以这样理解:当且仅当语句是一个赋值表达式,且表达式的右边还是一个没有返回值的函数(或者返回值为空,比如光写一个return,没有任何参数)时,那么lua会自动为表达式左边的变量赋上nil值。
菜鸟教程:若变量个数 > 值的个数 ,则按变量个数补足nil
不过看下列代码:
> function a()
>> end
> function f(i)
>> i = i + 1
>> end
> function t(...)
>> local args = {...}
>> print(args[1],args[2])
>> end
> t(nil,nil)
nil nil
> t(a(),a())
nil nil
> f(a())
stdin:2: attempt to perform arithmetic on local 'i' (a nil value)
stack traceback:
stdin:2: in function 'f'
stdin:1: in main chunk
[C]: ?
>
其实“赋值表达式”这个说法不准确,应该说是“发生赋值操作的语句”。
【附录】
> a = {false,false}
> for k,v in ipairs(a) do
>> print(k,v)
>> end
1 false
2 false
事实证明,只有为nil的value不会输出,为false的value仍然可以输出。
所以菜鸟教程上提供的这套迭代器实现原理是不准确的