Lua 快速上手指南

Posted tms不熬夜

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Lua 快速上手指南相关的知识,希望对你有一定的参考价值。

注: 本文基于 Lua 5.1

#1. 安装

Linux 最简单, 直接 clone 之后 make install 即可:

git clone https://github.com/LuaJIT/LuaJIT.git
cd LuaJIT
make && sudo make install

MacOS 的话要设置环境变量 MACOSX_DEPLOYMENT_TARGET, 其他和 Linux 一样:

git clone https://github.com/LuaJIT/LuaJIT.git
cd LuaJIT
MACOSX_DEPLOYMENT_TARGET=11.2 make && sudo make install

安装成功之后会提示创建链接到 bin 目录, 最好创建一个, 这样可以直接在命令行里使用 luajit 命令.

==== Successfully installed LuaJIT 2.1.0-beta3 to /usr/local ====

Note: the development releases deliberately do NOT install a symlink for luajit
You can do this now by running this command (with sudo):

  ln -sf luajit-2.1.0-beta3 /usr/local/bin/luajit

Window 的话, 先装好 Visual Studio, 然后打开PowerShell:

git clone https://github.com/LuaJIT/LuaJIT.git
cd LuaJIT/src
msvcbuild

装好之后就可以开始使用 luajit 了. 创建一个 lua 文件 hello.lua:

-- hello.lua
print("Hello Lua")

然后用 LuaJIT 执行这个文件:

luajit hello.lua
Hello Lua

这就是最简单的 Lua 程序了 o^ ^o

#2. 基本语法

Lua 的变量分为全局变量和局部变量, 声明局部变量要加关键字 local:

a = 1 -- 全局变量

local b = 2 -- 局部变量

Lua 的全局对象是_G, 标准库和全局变量都位于这个对象内. 可以把_G的属性打印出来看看. 修改 hello.lua 成这样:

for k, v in pairs(_Gdo
    print(k, v)
end

执行, 得到:

_G的属性列表


_G的属性可以分为这几类:

  • 类型和类型转换: type, tonumber, tostring.
  • 工具函数: assert, print, next, pairs, ipairs, getmetatable, setmetatable, getfenv, setfenv, rawget, rawset, rawequal, unpack, select.
  • 错误处理: error, pcall, xpcall.
  • 编译器相关: jit, load, loadstring, loadfile, dofile.
  • GC: collectgarbage, gcinfo,
  • 标准库: package, require, coroutine, string, table, math, io, os, debug, bit.
  • 其他: _G, arg, _VERSION, newproxy, module

Lua 有8种基础类型: nil, boolean, number, string, function, userdata, thread, table. 其中 userdata 用于存 C 语言的指针, 另外7种都可以直接在 Lua 运行时里使用:

local a -- 这时候a被声明了但没赋值, 是nil型

a = true -- boolean

a = 1 -- number

a = "Hello Lua" -- string

-- 函数也是基本类型
local function print_type(x)
 print(type(x))
end

print_type(a) -- 将打印出: string

-- table相当于array + hashmap
a = {12345}
print_type(a) -- 将打印出: table

a = {
 x = 1,
 y = "Hello Lua"
}
print_type(a) -- 将打印出: table

Lua 里的 thread 类型指的不是操作系统的线程, 而是 coroutine, 轻量级线程:

local function c(x)
    print("x = " .. x)
    local dx1 = coroutine.yield("yield from c")
    return x + dx1
end

local function d(y)
    print("y = " .. y)
    local dy1 = coroutine.yield("yield from d")
    return y + dy1
end

local co = coroutine.create(function(x, y)
    x = c(x)
    y = d(y)
    dx2, dy2 = coroutine.yield("yield from co")
    return x + dx2, y + dy2
end)

local x, y = 11000
print(coroutine.resume(co, x, y))
print(coroutine.resume(co, 1))
print(coroutine.resume(co, 100))
print(coroutine.resume(co, 2200))
print(coroutine.resume(co))

执行结果:

coroutine的执行结果


从上面的例子可以看到, Lua 可以同时赋多个值, 也可以 return 多个值, 且 coroutine 可以在各个地方被调用. Coroutine 的返回值是 coroutine状态 + yield 返回值的形式.

Lua 提供了一些非常有用的工具函数来构造表达式:

-- 输出一列, 1 2 3 4 5
for i = 15 do
 print(i)
end

local t = {12345}
-- 输出t中的所有元素
for i, v in ipairs(t) do
 -- Lua中数组索引从1开始
 print(i, v)
end

local n = 0
while n < 5 do
 n = n + 1 -- Lua没有++和+=
end

if n < 3 then
 print("n小于3")
else if n < 5 then
 print("n小于5")
else
 print("n大于等于5")
end

-- 只有nil和false是假
-- 其余全部都真, 包括空字符串和0
if not n then print("falsy"end

-- ~= 表示不等于
-- and or 结合起来就是二元表达式"? :"
local a = n ~= 0 and "n不等于0" or "n等于0"

#3. 标准库

列举一些 Lua 标准库里常用的函数:

string.format("Pi = %.2f"math.pi-- "Pi = 3.14"

string.match("<div>Hello Lua!</div>"">([^<>]+)<"-- "Hello Lua!"

local a = {321}

table.sort() --  a == {1, 2, 3}

table.concat(a, "|"-- "1|2|3"

table.insert(a, 4-- a == {1, 2, 3, 4}

table.remove(a, 2-- a == {1, 3, 4}

-- 把Hello Lua!写入文件texts.txt
local f = io.open("./texts.txt""a")
io.output(f)
io.write("Hello Lua!")
io.close()

os.time() -- Unix时间戳(单位秒), 形如 1613383439
os.date() -- Mon Feb 15 18:05:08 2021

bit.bnot(1-- -2

#4. 元表, 继承和OO

Lua 中所有table都可以设置描述元数据的 metatable(默认没有), 元数据包括加减乘除, 索引调用等运算符. 利用元表实现代理:

local a = {}
local b = {x = 1}

setmetatable(a, {
    __index = function(t, k)
        return b[k]
    end
})

print(a.x) -- 1

利用metatable, 可以构造继承的原型链:

-- Base class
local A = {is_A = true}
A.__index = A

function A:new()
    local new_instance = {}
    return setmetatable(new_instance, self)
end

-- Derivative class
local B = A:new()
B.is_B = true
B.__index = B

function B:new()
    local new_instance = {}
    return setmetatable(new_instance, self)
end

-- Instance
local c = B:new()
print(c.is_B) -- true
print(c.is_A) -- true

这里实例 c 的 metatable 是 B, 而 B 的 __index 属性是 B, 那么 c 中没有的属性会去B里找, 所以 c.is_B 是 true, 同理 c.is_A 也是 true. 这样就实现了一个原型链的继承. 至于冒号和 self 标识, 等架于:

-- 以下两种形式完全等架
function A:new()
    local new_instance = {}
    return setmetatable(new_instance, self)
end

A.new = function(A)
    local new_instance = {}
    return setmetatable(new_instance, A)
end

冒号是一个语法糖, 会把它前面的对象作为 self 传给函数体.

#5. 模块和模块管理

Lua 早期的模块设计有些问题, module 函数现在已经不推荐了. 现在的模块加载通过 require 来进行:

-- a.lua
local a = {x = 1}
return a

-- hello.lua
local a = require "./a"
print(a.x) -- 1

不过 require 的机制是从固定的路径开始找包, 所以引用相对路径的模块时需要写相对主入口的路径. 模块本身的返回值会作为 exports, 可以是任意类型的值.

每个语言都有自己流行的包管理器, Java 有 maven, NodeJS 有 npm, Rust 有 cargo, Python 有 pip 等等. Lua 主流的包管理器是 LuaRocks.

LuaRocks首页


#6. 常用软件包

Lua 语言本身比较精简, 这也意味着语言的核心比较薄, 很多实用的库需要借助社区. 这里列举一些非常有必要使用的软件包:

  • stdlib. 强化版的标准库, 提供了算法, 数据结构, 函数式编程所需要的工具函数和类型.
  • LuaDate. 更方便的处理时间和日期.
  • LPeg. 更方便的正则.
  • busted. 单元测试的好工具.
  • LuaSocket. coroutine + socket, 异步网络编程的基石.
  • Moses. 函数式编程的工具库, 和stdlib之间选一个即可.
  • Lapis. 全面强大开箱即用的 Web 框架.

#7. 资源及社区

  • Lua 用户的全能工具书: http://lua-users.org/wiki/
  • OpenResty的官方博客 https://blog.openresty.com/en/
  • 开源电子书OpenResty最佳实践: https://moonbingbing.gitbooks.io/openresty-best-practices/content/
  • Lua 语言手册: https://www.lua.org/manual/5.1/manual.html
  • Lua 最初的设计论文 https://www.lua.org/semish94.html
  • 15分钟学会Lua: http://tylerneylon.com/a/learn-lua/


以上是关于Lua 快速上手指南的主要内容,如果未能解决你的问题,请参考以下文章

Lua快速上手

Lua快速上手

挑战一晚上从零入门lua语言,直接对标Python快速上手

快速上手React:

Lua脚本语言快速入门手册

Lua 5.3 -- SOL2.0 用户指南