Lua_Real_Programming

2021-03-02 程式設計師不是碼農

《Programming in Lua》的第二部分,主要介紹Lua中的閉包,模式匹配,日期時間表示,數據結構實現,編譯執行和錯誤方式,以及模塊(Modules)和包(Packages)的概念。

Lua的函數function屬於first-class的值, 也就是function同Lua中的其他類型number、string、table等所處的地位一樣,function也可作為一個變量存儲在table中。

那麼如何理解function是為first-class呢?以下通過兩種函數申明方式來進行解釋

這兩種聲明方式都是申明一個foo的函數,實現2 * x的功能。

第2種申明可如此理解:右側函數定義作為一條申明語句,創建一個類型為function的值,並把它賦予foo這個變量。甚至,可以理解在Lua中所有的函數都是匿名的,我們平常用到的函數比如print,只不過是把print作為一個變量保存了對應的函數而已。


使用table.sort來舉例說明匿名函數的便利性,根據如下network中name這種欄位的字母逆序進行排序


函數聲明方式

對於局部函數,需要注意遞歸的情況,如下申明會出現函數未定義情況。


閉包

先看如下例子:

以上就是一個閉包,newCounter返回一個匿名函數,而這個匿名函數用到了newCounter中定義的local變量count,這個count就是所謂的上值(up-value),每次調用這個返回的匿名函數比如c1(),這個count貌似已經不在作用域內了,因為newCounter已經返回了,於是,Lua中採用閉包來處理和解決這種情況,每一次的調用,這個count的值會加一併保存。當創建一個新的匿名函數比如c2,c2的count跟c1擁有的count是完全分開獨立,互不幹擾的,也就是說c2產生了一個新的閉包。因此c1和c2是基於同一個匿名函數的不同閉包。


閉包讓Lua函數的功能變得更強大,以下是使用閉包的例子:

Lua模式匹配的實現代碼不到600行,沒有實現所有POSIX正則表達式的全部功能,但是Lua模式匹配功能強大,提供了很多feature是在標準的POSIX中很難做到的。


模式匹配相關函數

string.gsub, 這個接口之前已有介紹,不再贅述。


string.find

string.find (s, pattern [, init [, plain]])


尋找字符串s中pattern匹配的位置,匹配成功則返回兩個索引值(pattern的起始和終止位置),否則返回nil。


第三個可選參數init表明從哪裡開始搜索,其默認值是1


第四個可選參數plain表明是否為普通的字符串子串的搜索,不考慮模式匹配,如下:


string.match

string.match (s, pattern [, init])

跟string.find類似,但是其不是返回成功匹配的位置,而是返回成功匹配的內容,第三個默認參數init同樣為指定搜索起點。例子如下:


string.gmatch

string.gmatch(s, pattern)

返回一個迭代器函數,遍歷字符串中所有出現的pattern。


Patterns模式

Lua中使用%來作為轉義字符,常用字符含義如下


所有轉義字符的大寫,表示其補集,例如%A代表所有的非字母字符(%a為所有字符),如:


在Lua的模式中有一些字符具有特殊含義,被稱為Magic Characters, 如下:


Lua提供了4種修改器如下:


Exercise

請編寫一個函數split,該函數接受兩個參數,第一個參數是字符串,第二個參數是分隔符模式:


Lua中日期和時間有兩種表示方式:一種是整數形式,一種是table形式(日期table有以下這些域:year, month, day, hour, min, sec, way, yay, and isdst)。


os.time


os.date

其功能跟os.time相反,是將數字表示的時間和日期轉換成date table或者字符串等更加易讀的形式。

例如:


Date-Time操作

計算從此刻起40天以後那天的日期


Lua可以用table高效的實現數組,列表,隊列,集合等數據結構。


Arrays數組


Linked List列表


Queue隊列


Sets集合

將元素作為key放入table中,value置為true即可


String buffer字符串緩存

假定我們需要從文件中一行行讀取數據,可以選用以下方法:

這種方式效率極低,前面我們也提高過..進行字符串拼接是很低效的(一次拼接就是一個內存分配和字符移動)。因此可以選用更為高效的方式table.concat

Compilation, Execution, and Errors

Compilation

loadfile從文件中加載Lua代碼,只編譯代碼並將編譯結果作為函數返回,dofile是基於loadfile,會執行函數,可定義如下:

dofile更加完整,但是loadfile更加靈活,可只編譯一次,運行多次,而dofile每次運行都需要編譯,開銷大。

load跟loadfile功能類似,但是load不是從文件中讀取Lua代碼,而是從字符串或者函數中讀取,如:


在加載定義了函數的代碼塊時,有一個坑需要注意,lua中定義是需要通過賦值的:

當使用loadfile加載上述兩個文件時,加載foo1.lua後foo函數是沒有被定義,需要執行之後才可使用,而foo2.lua被加載後foo可直接使用,如下:


Errors

處理錯誤的方式:

可以使用pcall在lua代碼內部處理錯誤,不過使用pcall是看不到traceback的,因為其在返回錯誤代碼時就已經銷毀了調用棧。

Modules and Packages (模塊和包)

模塊:是能夠通過函數require加載,然後返回一個table,任何模塊導出的函數和常量,都定義在table中,這個table可以看作是一個命名空間。

Packages:由許多模塊組成。

模塊在lua中不是first-class,其不能作為參數傳遞給函數。

require加載模塊時,會從package.path路徑中去搜索,如果找到了對應文件,就通過loadfile進行加載。如果package.path中不能找對應的lua文件,就會從c庫中去搜索,即package.cpath,如果在c庫中找到了,就通過package.loadlib去找luaopen_modname的函數,其中modname為模塊名稱,luaopen_modname表示一個lua函數。


路徑搜索

require搜索路徑由一系列模版組成,模版之間用;隔開,如下;

如果調用require sql,直接用sql替換上述路徑中的?,那麼其搜索順序如下:

以下為實現一個類似package.searchpath的例子

首先要把modname中的.換成/,然後將modname替換path中的?。


Lua中實現模塊的方法

定義一個table,將所有函數放入table中,並返回table即可:

主要介紹Lua中閉包概念以及其用途,Lua的模式匹配,日期時間的兩種表現形式以及相關轉換接口,如何使用table實現其他數據結構如數組,列表,隊列,集合等,實現,編譯執行和錯誤方式,最後介紹了模塊(Modules)和包(Packages)的概念。


參考:

http://www.lua.org/pil/

http://www.lua.org/manual/5.3/manual.html#lua_call

陌生的人,請給我一支蘭州

相關焦點

  • 【物聯網學習---番外篇】Lua腳本編程掃盲
    其它特性:Lua還具有其它一些特性:同時支持面向過程(procedure-oriented)編程和函數式編程(functional programming);自動內存管理;只提供了一種通用類型的表(table),用它可以實現數組,哈希表,集合,對象;語言內置模式匹配等。
  • 【Lua篇】《Lua程序設計》全書知識萬字總結!
    這部分屬於其它語言和lua之間交互的內容。如果需要給項目接入lua或者想看懂xlua、tolua這種lua插件,那麼這部分內容也是必看的。第1章 開始1.1 程序塊程序塊,即chunk,由一行或多行lua可執行的代碼構成。下面兩段代碼,一個是程序塊一個不是。
  • WHY TEACH KIDS PROGRAMMING?
    What are the benefits of teaching programming? And finally, how to introduce programming during the very first years of primary school? Read this article and find out for yourself.
  • Lua API深入分析(一)
    準備知識:1.lua_State在lua API中,幾乎所有函數的都有一個lua_State類型的參數,lua_State數據包括當前腳本環境的運行狀態信息,還會有gc相關的信息。luaL_newstate用於創建一個新的lua_State,lua API調用時操作會在第一個參數傳入的lua_State上進行,lua_close用於關閉釋放lua_State。
  • Lua 5.3.0 (beta) 發布
    Lua 5.3.0 (beta) 發布,此版本現已提供測試:http://www.lua.org/work/lua-5.3.0-
  • 國內大講堂-Lua培訓(上篇)
    2.1 所有語言都開始於Hello World如果你安裝了lua,那麼可以使用lua命令,進入到lua的交互模式中。之後輸入的內容會被lua執行,比如列印了一個字符串Hello World。lua的注釋語法很簡單:單行注釋 -- 多行注釋 --[[  注釋內容 --]]2.2 Lua的數據類型有8種數據類型,如下表:
  • redis源碼學習之lua執行原理
    ;lauxlib.h>#include <lualib.h>int main(void){  //定義一段lua函數 char lua_func[] = "function hello(v) return v end"; //創建luaState lua_State* L = luaL_newstate();    //加載lua_func中內容為一個
  • 移植Lua到ARM平臺
    交叉編譯器:arm-linux-gcc 4.3.2版本(如果你不知道怎麼搭建交叉編譯環境,可以參考我的另一篇文章:http://hi.baidu.com/hqwfreefly/blog/item/8364fed7b3f58dc950da4b5f.html)3.Lua5.1版本源碼移植步驟:1下載Lua原始碼:http://www.lua.org
  • Nginx與Lua的執行順序和步驟說明
    lua腳本,常用於全局變量的申請。該階段不能運行Output API、Control API、Subrequest API、Cosocket APItimer:三、ngx_lua運行指令ngx_lua屬於nginx的一部分,它的執行指令都包含在nginx的11個步驟之中了,不過ngx_lua並不是所有階段都會運行的;1、init_by_lua、init_by_lua_file
  • 我們能用lua做什麼
    nginx-lua模塊最終,我們找到了nginx-lua?模塊。這個模塊會在每個nginx的worker_process中啟動一個lua解釋器,在nginx處理http請求的11個階段中,你可以在其中的多個階段用lua代碼處理請求。這二者的結合,給我們的web開發帶來了新的思路。下面我就來說下導航目前是如何使用它來解決問題的。
  • 觸動精靈,觸摸精靈-lua腳本入門
    觸動精靈,觸摸精靈最近比較火,可是沒有lua腳本基礎的人可能上手有點難,這篇經驗就介紹一下lua的入門。lua的入口函數在哪裡?lua沒有入口函數,按照順序 從上到下 執行暴漏在function以外的語句知道了所謂的入口函數,那這裡介紹經典程序 「hello world!」內容如下:print("hello world!"); --我是執行的第一條語句注釋應該怎麼用1、單行注釋中,連續兩個減號"--"表示注釋的開始,一直延續到行末為止。相當於C++語言中的"//"。
  • 在Nginx使用Lua擴展功能
    /download/LuaJIT-2.0.4.tar.gz$ wget https://github.com/simpl/ngx_devel_kit/archive/v0.3.0.tar.gz$ wget https://github.com/openresty/lua-nginx-module/archive/v0.10.5.tar.gz創建Nginx運行的普通用戶$ useradd
  • dlua 0.1 發布,gdb 風格的 lua 調試器
    dlua 是一個類似 gdb 的 lua 調試器。
  • 基於ngx_lua模塊的WAF開發實踐
    0x00 常見WAF簡單分析WAF主要分為硬體WAF和軟體防火牆,硬體WAF如綠盟的NSFOCUS Web Application Firewall,軟體防火牆比較有名的是ModSecurity,再就是代碼級別的ngx_lua_waf。
  • LTUI v1.7 發布,一個基於 Lua 的跨平臺字符終端 UI 界面庫
    此框架源於xmake中圖形化菜單配置的需求,類似linux kernel的menuconf去配置編譯參數,因此基於curses和lua實現了一整套跨平臺的字符終端ui庫。 而樣式風格基本上完全參照的kconfig-frontends,當然用戶也可以自己定製不同的ui風格。
  • 機器人離線編程揭秘 Demystifying Robot Offline Programming
    Post processors turn programming code into a language the robot can understand. Different robot manufacturers each have their own proprietary programming languages.
  • 深入解析Lua腳本加密技術,給遊戲代碼加上「緊箍咒」
    二、Lua現有的保護對於這種腳本解釋性語言,從代碼保護的角度跟它自身所表現的形式是密不可分的,對於Lua而言,目前市面上手遊包中可以看到的主要是lua源碼,luac,luajit三種的表現形式,接下來會詳細的介紹每一種形式以及自身現有的保護以及所暴漏出來的優缺點。
  • Unity遊戲開發-Lua更新運行時代碼!
    最近沉迷lua腳本熱更,想說這個可以提高多少菜雞的調試效率,找了網上好多文章,但是都不行,嘗試了很久,並且自己測試和學習,寫了一遍,勉強能熱更了。
  • 賴勇浩:動態大比拼Python、Lua和Ruby
    譯者按:Python、lua和ruby在C/C++是日漸式微的情況下,在java/.net的圍殲中努力抗爭的三個當紅小生。·         Ruby has arguably the simplest syntax, with no real rules exceptions. Especially true for OOP enthusiasts.
  • Lua你不得不學的乾貨
    Lua中成員函數的定義應該約定一種形式而不要點和冒號同時使用在lua中面向對象編程的時候都要用冒號使用冒號聲明函數的時候會把self作為參數隱藏在裡面,如果這個時候用點就會報錯-- 基礎類方法 newfunction