一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

腳本之家,腳本語言編程技術(shù)及教程分享平臺!
分類導(dǎo)航

Python|VBS|Ruby|Lua|perl|VBA|Golang|PowerShell|Erlang|autoit|Dos|bat|

服務(wù)器之家 - 腳本之家 - Lua - 深入解讀Lua中迭代器與泛型for的使用

深入解讀Lua中迭代器與泛型for的使用

2020-05-07 11:27林壽山 Lua

在Lua中,迭代器常被寫為函數(shù)而被調(diào)用返回下一個元素,而for循環(huán)調(diào)用迭代器函數(shù)則使得迭代更強強大,下面我們就來深入解讀Lua中迭代器與泛型for

泛型for原理

迭代器是一種可以遍歷集合中所有元素的機制,在Lua中通常將迭代器表示為函數(shù),每調(diào)用一次函數(shù),就返回集合中“下一個”元素。每個迭代器都需要在每次成功調(diào)用之間保持一些狀態(tài),這樣才能知道它所在的位置及如何步進到下一個位置,closure就可以完成此項工作。下面的示例是列表的一個簡單的迭代器:

?
1
2
3
4
function values(t)
 local i = 0
 return function() i = i + 1; return t[i] end
end

循環(huán)調(diào)用:

?
1
2
3
4
5
6
7
t = {10, 20, 30}
iter = values(t)
while true do
 local el = iter()
 if el == nil then break end
 print(el)
end

泛型for調(diào)用

?
1
for el in values(t) do print(el) end

泛型for為一次迭代循環(huán)做了所有的簿記工作。它在內(nèi)部保存了迭代器函數(shù),并在每次迭代時調(diào)用迭代器,在迭代器返回nil時結(jié)束循環(huán)。實際上泛型for保存了3個值:迭代器函數(shù)f、恒定狀態(tài)s、控制變量a。for做的第一件事就是對in后面的表達(dá)式求值,并返回3個值供for保存;接著for會以s和a來調(diào)用f。在循環(huán)過程中控制變量的值依次為a1 = f(s, a0),a2 = f(s, a1),依次類推,直至ai為nil結(jié)束循環(huán)。

先看一段代碼

?
1
2
3
for element in list_iter(t) do
 print(element)
end

在不往下看之前,我們可以先試圖根據(jù)我們已有的知識結(jié)構(gòu)去理解這段代碼。如果這樣,list_iter(t)應(yīng)該返回一個類似集合的東西,而我們已經(jīng)知道實際上只返回了一個匿名函數(shù),也就是迭代器。當(dāng)然,每次調(diào)用迭代器都可以得到一個元素,迭代器的所有的結(jié)果倒是可以看成一個集合。因素齊了,我們需要一個邏輯上的解釋,這個邏輯就是 泛型for的語義。
先看文法規(guī)定:

?
1
2
3
for <var-list> in <exp-list> do
 <body>
end

整個過程是這樣的:
首先,初始化,計算 in 后面表達(dá)式的值,表達(dá)式應(yīng)該返回 泛型for 需要的三個值:迭代函數(shù)、狀態(tài)常量、控制變量;與多值賦值一樣,如果表達(dá)式返回的結(jié)果個數(shù)不足三個會自

動用nil 補足,多出部分會被忽略。
第二,將狀態(tài)常量和控制變量作為參數(shù)調(diào)用迭代函數(shù)(注意:對于 for 結(jié)構(gòu)來說,狀態(tài)常量沒有用處,僅僅在初始化時獲取他的值并傳遞給迭代函數(shù))。

第三,將迭代函數(shù)返回的值賦給變量列表。
第四,如果返回的第一個值為 nil 循環(huán)結(jié)束,否則執(zhí)行循環(huán)體。
第五,回到第二步再次調(diào)用迭代函數(shù)。

更具體地說:

?
1
for var_1, ..., var_n in explist do block end

等價于

?
1
2
3
4
5
6
7
8
9
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

 泛型 for 在自己內(nèi)部保存三個值:迭代函數(shù)、狀態(tài)常量、控制變量。

迭代器的狀態(tài)

無狀態(tài)的迭代器本身不保存任何狀態(tài),for循環(huán)只會用恒定狀態(tài)和控制變量來調(diào)用迭代器函數(shù)。這類迭代器典型例子就是ipairs,下面是ipairs的Lua實現(xiàn):

?
1
2
3
4
5
6
7
8
local function iter(s, i)
 i = i + 1
 local v = s[i]
 if v then return i, v end
end
function ipairs(s)
 return iter, s, 0
end

當(dāng)for循環(huán)調(diào)用ipairs(list)時,會獲得3個值,然后Lua調(diào)用iter(list, 0)得到list, list[1],調(diào)用iter(list, 1)得到list, list[2],知道得到一個nil為止。

雖然泛型for只提供一個恒定狀態(tài)和一個控制變量用于狀態(tài)的保存,但有時需要保存許多其他狀態(tài)。這時可以用closure來保存,或者將所需的狀態(tài)打包為一個table,并保存在恒定狀態(tài)中。

閉包、迭代器和泛型for

到現(xiàn)在,Lua為我們準(zhǔn)備了三塊積木:閉包、泛型for和迭代器。一個循環(huán),我們可以利用閉包+迭代器,也可以使用泛型for+迭代器。那我們該怎么取舍呢?Lua也給出了建

議。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function iter (a, i)
 i = i + 1
 local v = a[i]
 if v then
  return i, v
 end
end
 
function ipairs (a)
 return iter, a, 0
end
 
for i, v in ipairs(a) do
 print(i, v)
end

這種情況是Lua最推薦的,迭代器不依賴upvalue,不產(chǎn)生閉包,狀態(tài)常量和控制變量借助泛型for保存,通過迭代器的參數(shù)傳遞給了迭代器。
再給一個書中的例子:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
local iterator -- to be defined later
 
function allwords()
 local state = {line = io.read(), pos = 1}
 return iterator, state
end
 
function iterator (state)
 while state.line do -- repeat while there are lines
  -- search for next word
  local s, e = string.find(state.line, "%w+", state.pos)
  if s then -- found a word?
   -- update next position (after this word)
   state.pos = e + 1
   return string.sub(state.line, s, e)
  else -- word not found
   state.line = io.read() -- try next line...
   state.pos = 1 -- ... from first position
  end
 end
 return nil -- no more lines: end loop
end

這樣好不好呢,Lua給的答案是否定的。書中有一段話說得很清楚:
我們應(yīng)該盡可能的寫無狀態(tài)的迭代器,因為這樣循環(huán)的時候由for 來保存狀態(tài),不需要創(chuàng)建對象花費的代價小;如果不能用無狀態(tài)的迭代器實現(xiàn),應(yīng)盡可能使用閉包;盡可能不

要使用table 這種方式,因為創(chuàng)建閉包的代價要比創(chuàng)建table 小,另外Lua 處理閉包要比處理table 速度快些。

延伸 · 閱讀

精彩推薦
  • LuaLua實現(xiàn)__add方法重載示例

    Lua實現(xiàn)__add方法重載示例

    這篇文章主要介紹了Lua實現(xiàn)__add方法重載示例,本文直接給出實現(xiàn)代碼,需要的朋友可以參考下 ...

    腳本之家7452020-04-24
  • LuaLua簡介、編譯安裝教程及變量等語法介紹

    Lua簡介、編譯安裝教程及變量等語法介紹

    這篇文章主要介紹了Lua簡介、編譯安裝教程及變量等語法介紹,本文同時講解了lua注釋語法、Lua命令行方式等內(nèi)容,需要的朋友可以參考下 ...

    junjie3632020-04-14
  • Lua深入探究Lua中的解析表達(dá)式

    深入探究Lua中的解析表達(dá)式

    這篇文章主要介紹了深入探究Lua中的解析表達(dá)式,對于其語法部分的說明和示例都超詳細(xì),極力推薦此文!需要的朋友可以參考下 ...

    腳本之家3542020-05-05
  • LuaLua中table庫函數(shù)方法介紹

    Lua中table庫函數(shù)方法介紹

    這篇文章主要介紹了Lua中table庫函數(shù)方法介紹,本文講解了concat、insert、maxn、remove、sort、foreachi等方法,需要的朋友可以參考下 ...

    腳本之家2502020-04-17
  • LuaLua教程(二):基礎(chǔ)知識、類型與值介紹

    Lua教程(二):基礎(chǔ)知識、類型與值介紹

    這篇文章主要介紹了Lua教程(二):基礎(chǔ)知識、類型與值介紹,本文講解了Hello World程序、代碼規(guī)范、全局變量、類型與值等內(nèi)容,需要的朋友可以參考下 ...

    腳本之家5922020-04-28
  • LuaLua中計算、執(zhí)行字符串中Lua代碼的方法

    Lua中計算、執(zhí)行字符串中Lua代碼的方法

    這篇文章主要介紹了Lua中計算、執(zhí)行字符串中Lua代碼的方法,類似JavaScript中eval函數(shù)的功能,在Lua中也可以實現(xiàn),需要的朋友可以參考下 ...

    腳本之家6322020-04-30
  • LuaLua和C語言的交互詳解

    Lua和C語言的交互詳解

    這篇文章主要介紹了Lua和C語言的交互詳解,Lua和C語言通過棧完成交互,本文結(jié)合代碼實例詳細(xì)講解了交互的方法,需要的朋友可以參考下 ...

    果凍想3702020-04-14
  • LuaLua中的元方法__newindex詳解

    Lua中的元方法__newindex詳解

    這篇文章主要介紹了Lua中的元方法__newindex詳解,本文講解了查詢與更新、監(jiān)控賦值、通過table給另一個table賦值等內(nèi)容,需要的朋友可以參考下 ...

    笨木頭8872020-04-09
主站蜘蛛池模板: 大杳蕉在线影院在线播放 | 午夜一区二区三区 | 国内精品在线观看视频 | 免费视频片在线观看 | 欧洲vodafone精品性 | 免费看男人使劲躁女人小说 | 人与动人物人a级特片 | 黑人群性xxx | 日本zzzzwww大片免费 | 四虎免费在线观看视频 | 日韩伦理在线看 | 国产欧美精品一区二区三区 | 午夜影院c绿象 | 无码毛片内射白浆视频 | 99视频九九精品视频在线观看 | 久久精品国产久精国产果冻传媒 | 99精彩视频在线观看 | 美女被灌浣肠失禁视频 | 色戒 完整版 | 色综合色狠狠天天综合色hd | 黄瓜视频黄版 | 欧美久在线观看在线观看 | 沟厕okn系列在线播放 | 激情小说欧美图片 | www一区| 丝袜捆绑调教视频免费区 | 国产成人99久久亚洲综合精品 | 四虎国产| 91制片厂果冻传媒杨柳作品 | 情趣内衣情趣玩具play | 男人的j伸到女人的屁股眼 男人吃奶动态图 | 国产精品毛片va一区二区三区 | 手机在线免费观看日本推理片 | www.日本免费 | 欧美同性猛男videos | 黑人干我 | xxxx18日本视频xxxxx | h日本漫画全彩在线观看 | 亚洲性视频在线观看 | 日本高h| 2021国产精品成人免费视频 |