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(_G) do
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 = {1, 2, 3, 4, 5}
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 = 1, 1000
print(coroutine.resume(co, x, y))
print(coroutine.resume(co, 1))
print(coroutine.resume(co, 100))
print(coroutine.resume(co, 2, 200))
print(coroutine.resume(co))
执行结果:
coroutine的执行结果
从上面的例子可以看到, Lua 可以同时赋多个值, 也可以 return 多个值, 且 coroutine 可以在各个地方被调用. Coroutine 的返回值是 coroutine状态 + yield 返回值的形式.
Lua 提供了一些非常有用的工具函数来构造表达式:
-- 输出一列, 1 2 3 4 5
for i = 1, 5 do
print(i)
end
local t = {1, 2, 3, 4, 5}
-- 输出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 = {3, 2, 1}
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 快速上手指南的主要内容,如果未能解决你的问题,请参考以下文章