为什么这适用于 Lua? - 对于 k, v in next, t, nil 做 print(k, v) end

Why this works in Lua? - for k, v in next, t, nil do print(k, v) end

我就是无法理解这个有效的 Lua 片段。

这个:

t = {'a', 'b', 'c'}
for k, v in next, t, nil do
  print(k, v)
end

Returns这个:

1   a
2   b
3   c

谁能解释一下,

他在评论中的回答全部归功于 Egor

来自Lua 5.3 manual:

A 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)
     if var_1 == nil then break end
     var = var_1
     block
   end
 end

所以原始语句转化为无限while循环,不断调用next()初始参数next(t, nil),并且在每次迭代中第二个参数被下一个索引替换在 t table 中。当最后 next(t, index_n) returns nil 时,循环中断。

在我看来,这是一种非常强大的遍历 table 的方法,因为 next() 几乎可以替换为任何可以完全控制迭代的函数。哇

扩展一下其他答案:

'generic for loop' 中涉及的值的更具描述性的命名如下:

for k, v1, v2, … in f_step, state, k0 do  …  end

它会像

一样循环
k,v1,v2,…=f_step(state,k0) ; if k==nil then break end ; k0=k ; --(…for body here…)
k,v1,v2,…=f_step(state,k0) ; if k==nil then break end ; k0=k ; --(…for body here…)
k,v1,v2,…=f_step(state,k0) ; if k==nil then break end ; k0=k ; --(…for body here…)
…

和 f_step 可以随意修改 state(尽管 pairs/next 不会那样做,再举一个例子, string.gmatch 甚至完全忽略 state k 并将所有不同的状态保持在一个闭包中(想想 'function' 如果你不还知道这个词)而不是。)


现在,pairs 所做的基本上只是

function pairs( t )
    -- (__pairs logic goes here, omitted for brevity)
    return next, t, nil
end

和常见的

for k, v in pairs( t ) do  …  end

基本上扩展到

for k, v in next, t, nil do  …  end

(除非 t 有一个带有 __pairs 的元表。)

现在有两个原因可以明确地写 next, t, nil 而不是 pairs – 混淆那些还不知道这件事的人,或者避免触发 __pairs。 (为了避免触发 __index/__newindex,你有 rawget/rawset,为了避免 __pairs,你明确地写了 next, t, nil。或者也许你定义 function rawpairs( t ) return next, t, nil end 并使用它……)