Skip to content

基础知识

Lua 使用 print() 函数输出字符串。

lua
print("Hello, world")

运行后你得到了结果。注意,它和其它 C-like 语言不一样,语句末尾不需要分号。

变量声明

Lua 是动态数据类型(弱类型)的语言,这意味着我们不能指定数据的基本类型。定义变量不需要关键字,直接写出变量名等于值即可。此变量默认是全局的,使用关键字 local 修饰才限制作用域在当前级别。

lua
a = 114514
b = "你是一个一个一个......啊!"
local c = false;

没有被声明的变量全部是 nil 类型的,值为 nil

lua
-- 输出 d,你会得到 nil
print(d)

Lua 支持批量声明。

lua
-- 这使得e和f都获得了指定值,但 g 仍然是 nil
e, f, g = 1919, "随便你戏弄"

注释

Lua 注释比较独特,行注释使用 -- 开头,段注释使用 --[[--]] 包裹。取消段注释可以将段前标识改为 ---[[,这对于调试来说很方便。

lua
-- print(1)
--- print(2)

--[[
 print(3)
--]]

---[[
 print(4)
--]]

-- 你最后只能得到 4 的输出

基本数据类型

Lua 中有八大基本数据类型:

数据类型名称描述
nil表示空,只有值 nil 属于该类,在条件表达式中相当于 false
boolean布尔表示真假,只包含两个值:falsetrue
number数值表示双精度类型的实浮点数。
string字符串表示字符序列。
function函数表示由 C 或 Lua 编写的函数。
userdata用户数据表示任意存储在变量中的 C 数据结构。
thread线程表示执行的独立线路,用于执行协同程序。
tableLua 中的表其实是一个关联数组(associative arrays),数组的索引可以是数字、字符串或表类型。表的创建是通过构造表达式来完成,最简单构造表达式是 {},用来创建一个空表。

数值和基本数值运算

Lua 中,数值(number)进制支持十进制和十六进制表达。

lua
a = 114.514
b = 0x1919

还可以使用科学计数法。

lua
-- 2x10^8
c = 2e8

运算方面除了常见的加减乘除,还支持幂运算和位运算。

lua
-- 8
print(2 ^ 3)
print(1 << 3)

字符串

Lua 中,字符串(string)用半角双引号对或单引号对包裹,涉及多行时,用 [[]] 包裹。

lua
a = "你是一个一个一个"
b = '吃得臭中臭,方撅人上人(喜'
c = [[你是内内个内内内个内个内内
内内个内内内个内个内内
内内个内内内个内个内内
阳光彩虹小白马]]

单行字符串想要换行必须使用转义字符 \n,但多行字符串中既可直接换行,也可以使用转义字符。

拼接两个字符串使用 .. 而不是传统的加号。

lua
d = "你是"
e = "内个"
g = d .. e -- g = "你是内个"

数值和字符串之间可以借助函数互相转化。

lua
h = "114514"
i = tonumber(h) -- tonumber() 函数将参数转化为数值
j = tostring(i) -- tostring() 函数将参数转化为字符串

如果转换失败(如参数为 nil 或参数不符合类型要求),则函数返回值为 nil。

字符串 str 的长度为 #str

lua
k = "你是...你知道我要说什么"
print(#k) -- 33。其中每个中文字符占长度 3,亦表明 Lua 存储文本采用 Unicode

函数

Lua 中,函数(function)的声明用关键字 function 表示,用 end 标识结束。

lua
-- 与 JS 类似的表达办法,只不过没有花括号包围
function a(m, n)
    print(m + n)
end
-- 另一种表达办法
b = function(m, n)
    print(m + n)
end

-- 两者是完全相同的

如果形参列表长度为 p,但传入的参数只有 q 个(p>q),则默认列表中靠前的参数被成功传入,后面的一律为 nil。

若函数不指定返回值,则函数总是为 nil返回使用关键字 return

lua
-- 无返回值
function c(n)
    r = n + 1
end
-- 有返回值
function d(n)
    r = n + 1
    return r
end

print(c(1), d(1)) -- nil 和 2

返回值可以是一个变量,也可以是一个变量序列。

lua
function e(m, n)
    m = m + 1 -- Lua 中没有自增的概念
    n = n + 1
    return m, n
end

--我们可以使用序列来接收它
f, g = e(114514, 1919)

Lua 中,(table)与广义表类似。它的元素可以为任何数据类型,且一个表内可以混装不同的数据类型。

表的声明用花括号对,调用用方括号对。

lua
a = {114514, "田所浩二", function() end, {}}

-- 表的索引从 1 开始计算
print(a[1]) -- 114514

越界调用会得到 nil。

向表插入元素可直接赋值,也可使用既有函数:

lua
b = {}
b[1] = 114514 -- 下标合法值取 [1, #b+1]
table.insert(b, 1919) -- 尾插元素
table.insert(b, 1, 810) -- 指定索引中插元素

-- #加表名可以获得数字下标的最大值
print(b[1], b[2], #b) -- 810、114514 和 3

从表移除元素:

lua
c = {114514, 1919, 810}
table.remove(c, 1) -- 指定索引移除元素

print(c[1]) -- 1919
print(table.remove(c, 1)) -- 1919。函数会返回移除掉的元素本身

表除了可以使用数字下标,还可以使用字符串下标:

lua
d = {
 a = 114514, -- a 虽然本身是字符串,但并不需要加引号对
    ["b"] = "你是", -- 想加引号对,就得捆绑一个方括号对
    c = "内个"
}

-- 调用可以沿用数字下标的形式,也可以用字符串下标独有的形式
print(d["a"]) -- 114514。这里写的 a 要用引号对包裹,注意
print(d.a) -- 114514。这个方式颇有面向对象的风味
print(#d) -- 0。该表内最大的数字下标就是 0

-- 可以向表中添加字符串下标的元素
d["motherfucker"] = "mf"
d.iloveyou = "ily"
print(d.motherfucker, d.iloveyou) -- mf 和 ily
提问:在以上这个演示中,d["a"] 是 d[1] 吗?

d[1] 指的是表中第一个没有字符串下标的元素,在这里就是 nil。

Lua 中存在一个 _G 表,它存放了所有的全局变量。上面提到的 table.insert() 函数,就是放在 table 表内的,table 本身再处于 _G 中。我们可以验证 insert() 的类型:

lua
print(_G["table"]["insert"]) -- function: addr
print(_G.table.remove) -- function: addr

布尔型和判断语句

Lua 中,布尔(boolean)用于表示真(true)假(false)。nil 参与判断时视为假,其它所有数据类型视为真。

lua
print(1 > 2) -- false
print(1 >= 1) -- true
print(1 == 1) -- true
print(1 ~= 1) -- false。~= 表示判断不等于

与或非逻辑分别用关键字 andornot。涉及它们的最小判断单元的值,为代表真/假的操作数的值。

lua
print(true and false) -- false
print(true or false) -- true
print(not true) -- false

print(1 and false) -- false。1 代表真,真并假为假,所以为 false
print(nil or "内个") -- "内个"。nil 代表假,"内个"代表真,假或真为真,所以为"内个"
print(not 0) -- false。0 为真,非真为假,所以为 false

print(nil and false) -- nil。两者都为假,假并假为假,返回第一个为假的操作数的值,所以为 nil
提问:nil and "true" or "false" 的值是什么?

"false"。nil 先和字符串 "true" 并上,得到 nil;再和字符串 "false" 或上,得到字符串 "false"。

条件判断语句结构能够根据判断语句的真值执行不同的操作。其基本结构如下:

lua
if sentence("判断语句 A") then
    print("A 真值为真的操作")
elseif sentence("判断语句 B") then
    print("B 真值为真的操作")
else
    print("A、B 真值均为假的操作")
end

循环

Lua 中,循环结构有三种,forwhilerepeat 结构。

for 结构相较于 C 中的,被大幅精简。

lua
-- 不指定步长,默认为 1
for i = 1, 10 do -- 这里的 i 是隐式 local 的,且具有只读属性
    print(i) -- 1、2、3、4、5、6、7、8、9、10
end
-- 指定步长
for i = 1, 10, 2 do
    print(i) -- 1、3、5、7、9
end
-- 指定负数步长
for i = 10, 1, -3 do
    print(i) -- 10、7、4、1
end

如果在 for 结构中尝试修改首行的局部变量,会被认为声明了一个新的全局变量。

while 结构和 repeat 结构相比起来更加简单。后者是先执行再判断,且条件属性从持续条件变为截止条件。

lua
n = 114514
while n > 114510 do
    print(n) -- 114514、114513、114512、114511
    n = n - 1
end

n = 114514
repeat
    print(n) -- 114514、114513、114512、114511
    n = n - 1
until (n <= 114510)

如果需要实现复杂功能,可以内置 if 结构加 break 语句。

更多

其实 Lua 作为一个关键字很少的脚本语言,基础知识并不足以满足现代开发。之后还有 IO、OOP 设计、协程等知识,如果你有兴趣,可以访问 Lua 的官方文档来自主学习。

精通 Lua 之后,不但可以做游戏脚本(最常见的用途),还可以涉足中小型程序开发。配合 C 的库,可以做到前后端通吃,节省你的大量时间。

遵从 CC BY-NC-SA 4.0