lua學(xué)習(xí)之迭代器與泛型for第一篇

迭代器與泛型 for 1

迭代器與 closure

  1. 「迭代器」是一種可以遍歷一種集合中的所有元素的機制
  2. 在 lua 中通常將迭代器表示為函數(shù)
  3. 每調(diào)用一次函數(shù),即返回集合中的「下一個」元素
  4. 每個迭代器都需要在每次成功調(diào)用之間保存一些狀態(tài)
  5. 這樣就知道它現(xiàn)在所在的位置以及如何步進到一下位置
  6. 一個 closure 就是一種可以訪問其外部嵌套環(huán)境中的局部變量的函數(shù)
  7. 這些變量可用于在成功調(diào)用之間保持狀態(tài)值
  8. 從而使 closure 可以記住它在一次遍歷中所在的位置
  9. 創(chuàng)建一個 closure 必須創(chuàng)建它的「非局部變量」
  10. 一個closure 結(jié)構(gòu)通常包含兩個函數(shù)
    1. closure 本身
    2. 創(chuàng)建該 closure 的工廠函數(shù)

while

  1. values 就是工廠薄扁,每次調(diào)用這個工廠率寡,就會創(chuàng)建一個新的 closure 即迭代器其本身
  2. 這個 closure 將它的想要保存在其外部變量 ti
  3. 每當(dāng)調(diào)用這個迭代器時迫卢,它就從列表 t 中返回下一個值
  4. 直到最后一個元素返回后,迭代器會返回 nil冶共,表示迭代的結(jié)束
function values(t)
    local i = 0
    return function () 
        i = i + 1
        return t[i]
    end
end
t = {123, 333, 444}
iter = values(t) -- 創(chuàng)建迭代器
while true do
    local element = iter() -- 調(diào)用迭代器
    if element == nil then
        break
    end
    print(element)
end

泛型 for

  1. 泛型 for 記錄了每一次迭代循環(huán)
  2. 它在內(nèi)部保存了迭代器函數(shù)乾蛤,因此不需要 iter 變量
  3. 它在每次新迭代時調(diào)用迭代器每界,并在迭代器返回 nil 時循環(huán)結(jié)束
function values(t)
    local i = 0
    return function () 
        i = i + 1
        return t[i]
    end
end
t = {123, 333, 444}
-- 泛型 for
t = {123, 333, 444}
for element in values(t) do
    print(element)
end

高級用法

  1. 遍歷當(dāng)前輸入文件中所有單詞的迭代器
  2. 需要保持的值
    1. 當(dāng)前行的內(nèi)容
    2. 以及該行所處的位置
  3. 使用 string.find 在當(dāng)前行中調(diào)用,以當(dāng)前位置作為起始位置來搜索一個單詞
  4. 使用模式 %w+ 用來表示一個「單詞」家卖, 英語匹配一個或多個文字或數(shù)字字符
  5. 如果找到了一個單詞眨层,迭代器將當(dāng)前位置更新為該單詞之后的第一個字符,并返回該單詞
  6. 否則上荡,迭代器讀取新的一行并重復(fù)這個搜索過程
  7. 若沒有剩余的行趴樱,則返回 nil, 以此表示迭代的結(jié)束。
-- 編寫迭代器
function allwords()
    local line = io.read() -- 當(dāng)前行
    local pos = 1 -- 一行中的位置
    return function () -- 迭代器函數(shù)
       while line do --  只要 line 不為 nil 循環(huán)執(zhí)行
            -- 返回開始位置和結(jié)束位置 
            local start, end = string.find(line, "%w+", pos)
            if s then -- 是否找到一個單詞
                pos = e + 1 -- 找到一個單詞榛臼,則移到這個單詞的下一個位置
                return string.sub(line, s) -- 返回該單詞
            else
                line = io.read() -- 這一行沒找到伊佃,嘗試讀取下一行
                pos = 1
            end
       end
       return nil -- 沒有剩余行了,遍歷結(jié)束
    end
end

-- 調(diào)用迭代器
for word in allwords() do
    print(word)
end

泛型 for 的語義

  1. 上述的迭代器需要為每一個新的循環(huán)創(chuàng)建一個新的 closure沛善,開銷很大
  2. 泛型 for 在循環(huán)過程內(nèi)保存了迭代器函數(shù)
  3. 保存了 3 個值
    1. 一個迭代器函數(shù)
    2. 一個恒定狀態(tài)
    3. 一個控制變量
-- var-list 變量列表 , exp-list 表達式列表, 多個元素可用 , 逗號分割
-- 通常表達式列表只有一個元素航揉,即只有一句對迭代器工廠的調(diào)用
for <var-list> in <exp-list> do
    <code block>
end

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

for line in io.lines() do
    io.write(line, "\n")
end
  1. 變量列表的第一元素稱為「控制變量」,在循環(huán)過程中該值絕不會為 nil金刁,當(dāng)它為 nil循環(huán)結(jié)束
  2. for 首先會先對 in 后面的表達式求值帅涂,這些表達式應(yīng)返回 3 個值for 保存
    1. 迭代器函數(shù)
    2. 恒定狀態(tài)
    3. 控制變量的初值
  3. 類似多重賦值,即只有最后一個表達式才會產(chǎn)生多個結(jié)果
  4. 只會保留前 3 個值尤蛮,多余的值被丟棄媳友,不足的話,用 nil 補足
  5. 初始化步驟后产捞,for 會以恒定狀態(tài)和控制變量來調(diào)用迭代器函數(shù)
  6. 然后 for迭代器函數(shù)的返回值賦予變量列表中的變量
  7. 如果變量列表中的第一個元素(即控制變量)的返回值為 nil醇锚,則循環(huán)終止
  8. 否則,for 執(zhí)行循環(huán)體坯临,然后再次調(diào)用迭代器函數(shù)焊唬,并重復(fù)這個過程
  9. for 構(gòu)建的角度來說,恒定狀態(tài)的內(nèi)容與 for 本身是完全無關(guān)的看靠。for 只是保存了初始化中返回的值赶促,并在調(diào)用迭代器函數(shù)時傳入該值。
for var_1, ..., var_n in <exp-list> do
    <code clock>
end

-- 上述代碼等價于如下代碼s
do
   -- _f 為迭代器函數(shù)挟炬,_s 為恒定狀態(tài)鸥滨,控制變量的初值為 a0
   local _f, _s, _var = <exp-list>
   while true do
        local var_1, ... var_n = _f(_s, _var)
        _var = var_1
        if _var == nil then
            break
        end
    end
    <code block>
end

  1. _f 為迭代器函數(shù),_s 為恒定狀態(tài)谤祖,控制變量的初值為 a?
  2. 在循環(huán)過程中控制變量的值依次為 a? = f(s, a?) 婿滓、a? = f(s, a?) 以此類推
  3. 直至 ainil 結(jié)束循環(huán)
  4. 如果 for 還有其他變量,那么 他們也會在每次調(diào)用 f 后獲得額外的值
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末粥喜,一起剝皮案震驚了整個濱河市空幻,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌容客,老刑警劉巖秕铛,帶你破解...
    沈念sama閱讀 222,590評論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異缩挑,居然都是意外死亡但两,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,157評論 3 399
  • 文/潘曉璐 我一進店門供置,熙熙樓的掌柜王于貴愁眉苦臉地迎上來谨湘,“玉大人,你說我怎么就攤上這事芥丧〗衾” “怎么了?”我有些...
    開封第一講書人閱讀 169,301評論 0 362
  • 文/不壞的土叔 我叫張陵续担,是天一觀的道長擅耽。 經(jīng)常有香客問我,道長物遇,這世上最難降的妖魔是什么乖仇? 我笑而不...
    開封第一講書人閱讀 60,078評論 1 300
  • 正文 為了忘掉前任,我火速辦了婚禮询兴,結(jié)果婚禮上乃沙,老公的妹妹穿的比我還像新娘。我一直安慰自己诗舰,他們只是感情好警儒,可當(dāng)我...
    茶點故事閱讀 69,082評論 6 398
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著眶根,像睡著了一般蜀铲。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上汛闸,一...
    開封第一講書人閱讀 52,682評論 1 312
  • 那天蝙茶,我揣著相機與錄音,去河邊找鬼诸老。 笑死隆夯,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的别伏。 我是一名探鬼主播蹄衷,決...
    沈念sama閱讀 41,155評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼厘肮!你這毒婦竟也來了岛请?” 一聲冷哼從身側(cè)響起纪挎,我...
    開封第一講書人閱讀 40,098評論 0 277
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎琳轿,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體汞窗,經(jīng)...
    沈念sama閱讀 46,638評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,701評論 3 342
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了示启。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,852評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡领舰,死狀恐怖夫嗓,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情冲秽,我是刑警寧澤舍咖,帶...
    沈念sama閱讀 36,520評論 5 351
  • 正文 年R本政府宣布,位于F島的核電站锉桑,受9級特大地震影響排霉,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜刨仑,卻給世界環(huán)境...
    茶點故事閱讀 42,181評論 3 335
  • 文/蒙蒙 一郑诺、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧杉武,春花似錦辙诞、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,674評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至祈搜,卻和暖如春较店,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背容燕。 一陣腳步聲響...
    開封第一講書人閱讀 33,788評論 1 274
  • 我被黑心中介騙來泰國打工梁呈, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人蘸秘。 一個月前我還...
    沈念sama閱讀 49,279評論 3 379
  • 正文 我出身青樓官卡,卻偏偏與公主長得像,于是被迫代替她去往敵國和親醋虏。 傳聞我的和親對象是個殘疾皇子寻咒,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,851評論 2 361

推薦閱讀更多精彩內(nèi)容