Lua入門記錄

學習資料

閱讀筆記,只是記錄了知識點和一些注意點,詳細的看上面提供的學習資料連接

  • Lua 基礎數據類型
    • nil(空)
    • boolean(布爾)
      • Lua 中 nil 和 false 爲「假」,其它全部值均爲「真」
    • number(數字)
    • string(字符串)
      • 使用一對匹配的單引號。例:'hello'。
      • 使用一對匹配的雙引號。例:"abclua"。
      • 字符串還能夠用一種長括號(即[[ ]])括起來的方式定義
      • Lua 字符串通常都會經歷一個「內化」(intern)的過程,即兩個徹底同樣的 Lua 字符串在 Lua 虛擬機中只會存儲一份
    • table (表)
      • 索引能夠是除 nil 之外的任意類型的值
    • function (函數)
      • 有名函數的定義本質上是匿名函數對變量的賦值
  • 表達式
    • 算術運算符
    • 關係運算符
      • Lua 語言中「不等於」運算符的寫法爲:~=
      • 只有當兩個變量引用同一個對象時,才認爲它們相等
    • 邏輯運算符
      • a and b 若是 a 爲 nil,則返回 a,不然返回 b (短路求值)
      • a or b 若是 a 爲 nil,則返回 b,不然返回 a (短路求值)
      • 對於 not,永遠只返回 true 或者 false
    • 字符串鏈接
      • 鏈接兩個字符串,可使用操做符".."(兩個點)
      • 使用 string 庫函數 string.format 鏈接字符串
      • 因爲 Lua 字符串本質上是隻讀的,所以字符串鏈接運算符幾乎總會建立一個新的(更大的)字符串
      • 使用table.concat() 來進行不少字符串的拼接
    • 優先級
      • 若不肯定某些操做符的優先級,就應顯示地用括號來指定運算順序。這樣作還能夠提升代碼的可讀性。
    • 正則表達式
      • 使用ngx.re.*進行正則處理
      -- 參數 "j" 啓用 JIT 編譯,參數 "o" 是開啓緩存必須的
          local m = ngx.re.match("hello, 1234", regex, "jo")
  • 控制結構
    • if-else
      • else 與 if 是連在一塊兒的,若將 else 與 if 寫成 "else if" 則至關於在 else 裏嵌套另外一個 if 語句
    • while
    • repeat
      • 執行 repeat 循環體後,直到 until 的條件爲真時才結束
    • for
      • Lua 標準庫提供了幾種迭代器,包括用於迭代文件中每行的(io.lines)、 迭代 table 元素的(pairs)、迭代數組元素的(ipairs)、迭代字符串中單詞的(string.gmatch)
      • 最好使用ipairs,ipairs() 內建函數是能夠被 JIT 編譯的
    • break,return 和 goto
      • return 若要寫在函數中間,則只能寫在一個顯式的語句塊內 或者 直接寫成do return end,不然會報錯
      • 提供 goto 代替 continue
  • Lua函數
    • 使用local修飾符標記局部函數
    • 變長參數使用"..."(三個點),若對性能敏感的代碼,應當避免使用此種形式
    • 函數的返回值容許函數返回多個值,返回多個值時,值之間用","隔開
    • 全動態函數調用
    local args = {...} or {}
        method_name(unpack(args, 1, table.maxn(args)))
    • 點號與冒號操做符的區別
      • 冒號操做會帶入一個 self 參數,用來表明 本身,冒號的操做,只有當變量是類對象時才須要
      • 點號操做,只是 內容 的展開
      local str = "abcde"
          print("case 1:", str:sub(1, 2))
          print("case 2:", str.sub(str, 1, 2))
  • 模塊
    • require 函數用來加載模塊,禁用module() 定義模塊
    • require 函數內不能進行上下文切換,因此不可以在模塊的頂級上下文中調用 cosocket 一類的 API
    • 局部變量
      • Lua 中的局部變量要用 local 關鍵字來顯式定義,不使用 local 顯式定義的變量就是全局變量
      • Lua 上下文中應當嚴格避免使用本身定義的全局變量。
      可使用一個 lj-releng 工具來掃描 Lua 代碼,定位使用 Lua 全局變量的地方。
      lj-releng 的相關連接:https://github.com/openresty/openresty-devel-utils/blob/master/lj-releng
    • 虛變量
      • 按照慣例以一個下劃線(「_」)來命名,用它來表示丟棄不須要的數值,僅僅起到佔位的做用
    • 非空判斷
      • 對於簡單類型的變量,咱們能夠用 if (var == nil) then 這樣的簡單句子來判斷
      • 判斷一個 table 是否爲 {}
      function isTableEmpty(t)
          return t == nil or next(t) == nil
      end
  • String庫
    • Lua 字符串內部用來標識各個組成字節的下標是從 1 開始的
    • string.byte(s [, i [, j ]])
    • string.char (...)
    • string.upper(s)
    • string.lower(s)
    • string.len(s)
      • 使用此函數是不推薦的。應當老是使用 # 運算符來獲取 Lua 字符串的長度。
    • string.find(s, p [, init [, plain]])
      • p參數儘可能不要使用模式匹配
    • string.format(formatstring, ...)
    • string.match(s, p [, init])
      • 目前並不能被 JIT 編譯,應 儘可能 使用 ngx_lua 模塊提供的 ngx.re.match 等接口
    • string.gmatch(s, p)
      • 目前並不能被 LuaJIT 所 JIT 編譯,而只能被解釋執行。應 儘可能 使用 ngx_lua 模塊提供的 ngx.re.gmatch 等接口。
    • string.rep(s, n)
    • string.sub(s, i [, j])
    • string.gsub(s, p, r [, n])
      • 此函數不能爲 LuaJIT 所 JIT 編譯,而只能被解釋執行。通常咱們推薦使用 ngx_lua 模塊提供的 ngx.re.gsub 函數。
    • string.reverse (s)
  • table庫
    • 下標從 1 開始
    • 取長度操做符寫做一元操做 #
    • 判斷數組大小
      • table.getn(t) 計算的是數組元素,不包括 hash 鍵值,以第一個 nil 元素來判斷數組結束
      • *# 只計算 array 的元素個數,實際上調用了對象的 metatable 的 __len 函數*
      • 必定不要使用 # 操做符或 table.getn 來計算包含 nil 的數組長度
      • 不要在 Lua 的 table 中使用 nil 值,若是一個元素要刪除,直接 remove,不要用 nil 去代替
    • table.getn 獲取長度
      • 對於有「空洞nil值」的狀況,table 的長度存在必定的 不可肯定性。
    • table.concat (table [, sep [, i [, j ] ] ])
    • table.insert (table, [pos ,] value)
    • table.maxn (table)
    • table.remove (table [, pos])
    • table.sort (table [, comp])
    • table.new 預分配 Lua table 空間
    • table.clear 釋放 table 空間
  • 日期時間函數
    推薦使用 ngx_lua 模塊提供的帶緩存的時間接口,如 ngx.today, ngx.time, ngx.utctime, ngx.localtime, ngx.now, ngx.http_time,以及 ngx.cookie_time 等
    • os.time ([table])
    • os.difftime (t2, t1)
    • os.date ([format [, time]])
  • 數學庫
    • math.rad(x) 角度x轉換成弧度
    • math.deg(x) 弧度x轉換成角度
    • math.max(x, ...) 返回參數中值最大的那個數,參數必須是number型
    • math.min(x, ...) 返回參數中值最小的那個數,參數必須是number型
    • math.random ([m [, n]]) 不傳入參數時,返回 一個在區間[0,1)內均勻分佈的僞隨機實數;只使用一個整數參數m時,返回一個在區間[1, m]內均勻分佈的僞隨機整數;使用兩個整數參數時,返回一個在區間[m, n]內均勻分佈的僞隨機整數
    • math.randomseed (x) 爲僞隨機數生成器設置一個種子x,相同的種子將會生成相同的數字序列
    • math.abs(x) 返回x的絕對值
    • math.fmod(x, y) 返回 x對y取餘數
    • math.pow(x, y) 返回x的y次方
    • math.sqrt(x) 返回x的算術平方根
    • math.exp(x) 返回天然數e的x次方
    • math.log(x) 返回x的天然對數
    • math.log10(x) 返回以10爲底,x的對數
    • math.floor(x) 返回最大且不大於x的整數
    • math.ceil(x) 返回最小且不小於x的整數
    • math.pi 圓周率
    • math.sin(x) 求弧度x的正弦值
    • math.cos(x) 求弧度x的餘弦值
    • math.tan(x) 求弧度x的正切值
    • math.asin(x) 求x的反正弦值
    • math.acos(x) 求x的反餘弦值
    • math.atan(x) 求x的反正切值
  • 文件操做
    實際中的應用,在 OpenResty 項目中應儘量讓網絡處理部分、文件 I/0 操做部分相互獨立,不要揉和在一塊兒
  • 元表
    • 元表 (metatable) 的表現行爲相似於 C++ 語言中的操做符重載
    • 兩個十分重要的用來處理元表的方法
      • setmetatable(table, metatable):此方法用於爲一個表設置元表。
      • getmetatable(table):此方法用於獲取表的元表對象。
    • 可被重載的元方法
      |元方法|含義|
      |--|--|
      | __add | + 操做 |
      | __sub | - 操做 其行爲相似於 "add" 操做 |
      | __mul | * 操做 其行爲相似於 "add" 操做 |
      | __div | / 操做 其行爲相似於 "add" 操做 |
      | __mod | % 操做 其行爲相似於 "add" 操做 |
      | __pow | ^ (冪)操做 其行爲相似於 "add" 操做 |
      | __unm | 一元 - 操做 |
      | __concat | .. (字符串鏈接)操做 |
      | __len | # 操做 |
      | __eq | == 操做 函數 getcomphandler 定義了 Lua 怎樣選擇一個處理器來做比較操做 僅在兩個對象類型相同且有對應操做相同的元方法時才起效 |
      | __lt | < 操做 |
      | __le | <= 操做 |
      | __index | 取下標操做用於訪問 table[key]|
      | __newindex | 賦值給指定下標 table[key] = value|
      | __tostring | 轉換成字符串|
      | __call | 當 Lua 調用一個值時調用|
      | __mode | 用於弱表(week table)|
      | __metatable | 用於保護metatable不被訪問|
  • Lua 面向對象編程
      • 使用表和函數實現面向對象
    • 繼承
      • 用元表實現
    • 成員私有性
      • 使用相似於函數閉包的形式來實現
  • FFI
    • FFI 庫,是 LuaJIT 中最重要的一個擴展庫
    • 詞庫解釋html

      名詞 解釋
      cdecl A definition of an abstract C type(actually, is a lua string)
      ctype C type object
      cdata C data object
      ct C type format, is a template object, may be cdecl, cdata, ctype
      cb callback object
      VLA An array of variable length
      VLS A structure of variable length
    • 在 lua 文件中使用 ffi 庫的時候,必需要有這一行:local ffi = require "ffi"
    • ffi.cdef
      • 語法:ffi.cdef(def)
      • 功能:聲明 C 函數或者 C 的數據結構
    • ffi.typeof
      • 語法:ffi.cdef(def)
      • 功能:建立一個 ctype 對象,會解析一個抽象的 C 類型定義
    • ffi.new
      • 語法:cdata = ffi.new(ct [,nelem] [,init...])
      • 功能:開闢空間,第一個參數爲 ctype 對象,ctype 對象最好經過 ctype = ffi.typeof(ct) 構建
    • ffi.fill
      • 語法:ffi.fill(dst, len [,c])
      • 功能:填充數據
    • ffi.cast
      • 語法:cdata = ffi.cast(ct, init)
      • 功能:建立一個 scalar cdata 對象。
    • 調用 C 函數
      1. 加載 FFI 庫。
      2. 爲函數增長一個函數聲明。這個包含在 中括號 對之間的部分,是標準 C 語法。
      3. 調用命名的 C 函數
      local ffi = require("ffi")
      
          ffi.cdef[[
          int printf(const char *fmt, ...);
          ]]
      
          ffi.C.printf("Hello %s!", "world")
    • 防止內存泄漏的方案
      1. 在調用 resource = ffi.C.xx_create 等申請資源的函數以後,當即補上一行 ffi.gc(resource, ...) 來註冊釋放資源的函數
      2. 有些時候,ffi.C.xx_create 返回的不是具體的 cdata,而是整型的 handle。這會兒須要用 ffi.metatype 把 ffi.gc 包裝一下
        ```
        local resource_type = ffi.metatype("struct {int handle;}", {
        __gc = free_resource
        })git

        local function free_resource(handle)
        ...
        endgithub

        resource = ffi.new(resource_type)
        resource.handle = ffi.C.xx_create()
        ```正則表達式

  • JIT
    ```
    能夠經過 ngx-lj-gc-objs 工具看到指定的 Nginx worker 進程裏全部 trace 對象的一些基本的統計信息:https://github.com/openresty/stapxx#ngx-lj-gc-objs編程

    咱們如何才能知道具體是哪一行 Lua 代碼上的哪個 NYI 原語終止了 trace 編譯呢?
    答案很簡單。就是使用 LuaJIT 安裝自帶的 jit.v 和 jit.dump 這兩個 Lua 模塊。這兩個 Lua 模塊會打印出 JIT 編譯器工做的細節過程數組

    完整的 NYI 列表:http://wiki.luajit.org/NYI緩存

    可使用 ab 和 weighttp 這樣的工具對相應的服務接口進行預熱,以觸發 LuaJIT 的 JIT 編譯器開始工做
    ```cookie

相關文章
相關標籤/搜索