TOC

Lua (2): 其他姿势

由于想了解一下 OpenResty, 先看看 Lua 的语法。

这是第二篇,接着说 Lua 基础语法。

迭代器

内置的两个迭代器函数,之前都用过了:

  • pair
  • ipair

无状态迭代器

function square(iteratorMaxCount, currentNumber)
    if currentNumber < iteratorMaxCount
    then
        currentNumber = currentNumber + 1
        return currentNumber, currentNumber * currentNumber
    end
end

-- ------------------------------------

for i, n in square, 3, 0
do
   print(i, n)
end

-- ------------------------------------

function squares(iteratorMaxCount)
    return square, iteratorMaxCount, 0
end  

for i,n in squares(3)
do
    print(i, n)
end

有状态迭代器

通过闭包 Closure 的方式,实现了迭代器状态的保留。

array = {"Lua", "Tutorial"}

function elementIterator(collection)
    local index = 0
    local count = #collection
    return function ()
        index = index + 1
        if index <= count
        then
          -- return the current element of the iterator
          return collection[index]
        end
    end
end

for element in elementIterator(array)
do
    print(element)
end

元表 metatable

给原有类型增加或者重载部分方法。

  • setmetatable(table, metatable)
  • getmetatable(table)

比如,print 方法会调用变量的 __tostring 方法,重载这个方法可以定义 print 时的输出:

arr = {1, 2, 3, 4}
arr = setmetatable(arr, {__tostring = function (self)
    local result = '{'
    local sep = ''
    for _, i in pairs(self) do
        result = result .. sep .. i
        sep = ', '
    end
    result = result .. '}'
    return result
end})
print(arr)  --> {1, 2, 3, 4}

协程 coroutine

不知道为什么协程类型的关键字是 thread,这有点让人容易误解。

x = coroutine.create(a_func) -- thread 类型
coroutine.create
coroutine.resume
coroutine.yield
coroutine.runing
coroutine.status
coroutine.wrap

用到的时候再来补充把。

基础操作

时间

采用 os 模块,应该都是系统调用。

  • os.time([table]) => 返回 UTC 时间戳,或者指定时间的时间戳。
  • table 包含 year, month, day, hour, min, sec, isdst
  • 至少包含年月日,时分秒默认是 12:00:00
  • table 会被当作本地时间
  • os.date([format[, time]]) 还是 C 库中的格式化字符串
  • os.difftime 返回两个时间戳之间的时间差(需要么?)
a = os.date("*t")
for k, v in pairs(a) do
    print(string.format("%s = %s", k, tostring(v)))
end
-- hour = 20
-- min = 4
-- wday = 1
-- day = 3
-- month = 7
-- year = 2021
-- sec = 43
-- yday = 185
-- isdst = false

print(os.date('%Y/%m/%d %H:%M:%S'))
-- 2021/07/03 20:06:31

文件 I/O

  • io 模块
local file = io.open('filepath', 'r')
io.input(file)
io.read() -- 一行
io.close(file)

file = io.input('filepath')
repeat
    line = io.read()
    if nil == line then
        break
    end
    print(line)
until (false)
io.close(file)

local file = io.open('filepath', 'r')
file:read() -- 一行
file:close()

io.read 可以传以下参数:

  • *I 默认参数,表示读一行
  • *a 整个文件
  • *n 读一个整数
  • 整数 表示读指定数量的字符。
file:seek()
io.tmpfile()
io.type(file)
io.flush()
io.lines() -- 可以传文件名作为参数

数学计算

math.pi
math.rad(x) -- 角度转弧度
math.deg(x) -- 弧度转角度
math.sin(x) -- 正弦
math.cos(x) -- 余弦
math.tan(x) -- 正切
math.asin(x) -- 反正弦
math.acos(x)
math.atan(x)

math.max(x, ...)
math.min(x, ...)

math.random([m[, n]]) -- [0, 1) or [1, m) or [m, n)
math.randomseed(x)

math.abs(x)
math.fmod(x, y)
math.pow(x, y)
math.sqrt(x)
math.exp(x) -- e^x
math.log(x)
math.log10(x)
math.floor(x)
math.ceil(x)

math.abs(x)
math.abs(x)
math.abs(x)
math.abs(x)
math.abs(x)

正则表达式

不符合 POSIX 规范!!!因为 regexp 实现相对太大,所以另外做了一套,当然功能就简单很多。

就是 string 的那几个模式匹配方法:

  • string.find
  • string.match
  • string.gmatch
  • string.sub
  • string.gsub

用的时候参考 5.4.1 – Patterns

参考资料与拓展阅读