一、在线虚拟机环境

LuatOS 在线模拟

二、变量

1. 变量声明

  • 全局变量

不加任何修饰符的默认情况下声明的变量即为全局变量.


-- 以下是全局变量

a = 1

b = 2
  • 局部变量

使用 local 修饰符将变量声明为局部变量.


local a = 1

local b = 2

所有没有被声明的变量默认为空.


print(a)

-- 输出为 nil
  • 声明多个变量并赋值

Lua中可以用以下语法同时声明多个变量并且赋值:


a, b = 1, 2

print(1, 2) 

2. 变量的数据类型

数字(number)类型

最基本的数字即为number类型, 且其拥有多种表示方法:


-- 十进制数字

a = 1

b = 2

-- 以十六进制表示的数字类型

c = 0x11 -- 等于 17

-- 科学计数法

d = 2e10 -- 等于 20000000000.0

字符串(string)类型

与其他语言相似, 在Lua中可以用双引号或单引号来表示一个字符串:


str1 = "hello world"

str2 = 'foo bar'

print(str1) -- 输出 hello world

print(str2) -- 输出 foo bar

Lua中可以使用双中括号来声明一个文本块:


str = [[

    114514

    1919

    810

]]

print(str)

Lua中可以使用字符串连接符号来进行字符串的连接:


a = 'foo'

b = 'bar'

c = a..b

print(c) -- 输出 foobar

使用tostring()函数可以将其他类型的变量转换为字符串:


a = 123

b = tostring(a)

print(type(b)) -- 输出 string

同时, 也可以使用tonumber()函数来将字符串变量转换为Number类型:


a = "10"

b = tonumber(a)

print(type(b)) -- 输出 number

-- 注意, 如果tonumber()转换失败, 则输出结果将为nil

c = "abc"

d = tonumber(c)

print(d) -- 输出 nil

使用#号获取字符串的长度:


a = "114514 1919 810"

print(#a) -- 输出 15

字符串(string)内建函数

string.char()

在Lua中的字符串类似其他语言, 本质上是一个字符(char)类型的数组. 对于 string.char(...)函数, 它可以接收一组ascii码值, 然后返回一个由这些字符组成的字符串.


s = string.char(0x30, 0x31, 0x32, 0x34)

print(s) -- 输出 0124

string.byte()

函数string.byte(x, y)接收两个变量, x为任意字符串, y则是该字符串中任意字符的下标, 该函数返回对应下标的字符的ascii码值


str = "hello"

n = string.byte(str, 2)  

print(n) -- 输出 101, 即e

print(string.char(n)) -- 输出 e

布尔(boolean)类型

与其他语言类似, Lua拥有布尔类型, 其值只有 true 和 false 两种


a = true

b = false

布尔值可以用比较符号得出, Lua支持的比较符号有以下几种


-- 小于

print(1 < 2)

-- 大于

print(1 > 2)

-- 小于等于

print(1 <= 2)

-- 大于等于

print(1 >= 2)

-- 等于

print(1 == 2)

-- 不等于

print(1 ~= 2)

同时, Lua使用 and、or 和 not 等关键字来作为逻辑连接词


a = true

b = false

-- a且b

print(a and b) -- 输出 false

-- a或b

print(a or b)  -- 输出 true

-- 非a

print(not a)   -- 输出 false

在Lua中, 只有nilfalse为成假赋值, 其他所有值均为成真赋值


a = nil -- 假

b = 0   -- 真

-- 由于无法进行类型转换, 因此直接使用两次求反运算来转换为布尔值

print(not not a) -- 输出 false

print(not not b) -- 输出 true

当使用逻辑连接词对非布尔值进行运算时, 将不一定会返回布尔值,

例如, 当多个变量以and相连时, 会返回第一个为成假赋值(false/nil)的变量:


a = "hello"

b = 0

c = false

print(a and b and c) -- 输出 false

a = nil

b = 0

c = 123

print(a and b and c) -- 输出 nil

当相连的变量中不含有成假赋值的变量时, 返回最后一个变量(右值)


a = "hello"

b = 0

c = 123

print(a and b and c) -- 输出 123

类似的, 对于or语句相连的变量, 会返回第一个成真赋值, 而当不存在成真赋值时, 返回最后一个变量(右值)


a = 'hello'

b = a

c = nil

print(a or b or c) -- 输出 hello

a = false

b = false

c = nil

print(a or b or c) -- 输出 nil

利用上述特性, 可以用逻辑连接词来构建一个三元表达式


a = 1

print(1 > 0 and "yes" or "no") -- 输出 yes

表(table)类型

表是一种类似数组的数据结构, 可以用一对大括号进行声明


-- 声明一个表

a = {}

print(type(a)) -- 输出 table

表中可以存放任意类型的元素, 除了数字型和字符串型外还可以存储函数, 甚至可以在表中嵌套表


a = {

    "hello",

    114514,

    function() end,

    {}

}

注意 表使用一对中括号+下标来存取元素, 而下标的起始数为1


a = {"hello", 123}

print(a[0]) -- 输出为 nil

print(a[1]) -- 输出为 hello

-- 使用等号可以直接为任意下标的元素赋值

a[5] = "foo"

print(a[5]) -- 输出为 foo

使用#符号也可以获取到表的长度


a = {123, 456}

print(#a) -- 输出为 2

表(table)的内建函数

  • 插入元素

使用table.insert(x, y)语句来为一个表插入元素, x为表名, y为任意变量


a = {} 

table.insert(a, "hello")

print(a[1]) -- 输出 hello

还可以使用table.insert(x, y, z)语句来在某个表的指定位置插入元素, x为表名, y为对应位置的下标, z为任意变量


a = {"hello", 123}

table.insert(a, 1, "foo") -- 在下标为1的位置插入元素, 即首位

print(a[1]) -- 输出为 foo
  • 删除元素

使用table.remove(x, y)来删除表中任意位置的元素, 其中x为表名, y为对于位置的下标


a = {"hello", 123}

table.remove(a, 1) -- 删除a表中下标为1的元素, 即"hello"

-- 删除元素后所有剩余元素向前移动一位

print(a[1]) -- 输出为 123

table.remove(x, y) 将返回其删除掉的元素


a = {"hello", 123}

local b = table.remove(a, 1)

print(b) -- 输出为 hello

表(table)的字符串(string)下标

Lua中的表还拥有类似Map的属性, 即可以使用字符串作为下标, 实现类似于key的效果.


a = {

    el1 = 1, --使用 "el1"作为下标

    el2 = 10

}

-- 注意 使用字符串下标时, 存取元素需要带有双引号来表示其下标, 否则会被认定为是一个变量

print(a["el1"]) -- 输出 1

当下标的命名符合变量的命名规范时, 还可以直接用 表名.下标名 来存取元素


a = {

    el1 = 1,

    el2 = 10

}

print(a.el2) -- 输出 10

全局表

在Lua中有一个特殊的表, 被称为全局表, 变量名为_G, 它存储了当前上下文中的所有全局变量


a = 114514

print(_G["a"]) -- 输出 114514

注意 _G 表存储了所有的全局变量, 包括之前用到的 table 实际上便是Lua中内建的一个表, 该表存储了与表有关的操作函数


print(_G["table"]) -- 输出 table: 0x10

print(_G["table"]["insert"]) -- 输出 function: 0x155

三、运算符

除了最基本的加减乘除运算, Lua还支持一些其他的符号.

  • 乘幂符号

乘幂符号用于计算x的y次方, 具体语法如下:


a = 10^5 -- 等于10的5次方

print(a) -- 输出为100000.0
  • 左移、右移

基本的二进制移位运算:


a = 1 << 3 -- 将1左移3位 即 001 → 010 → 100 = 8

print(a) -- 输出 8

四、 函数

  • 函数声明

一个最基础的函数声明如下:


function hello()

    -- 函数体

end

在Lua中, 函数本质上也是一种变量类型, 可以将函数名在左侧声明, 然后用等号连接:


hello = function()

    -- 函数体

end
  • 形式参数

函数的形式参数声明类似变量:


-- 此处声明了三个形式参数a, b, c

function f(a, b, c)

    -- 函数体

end

类似变量, 当形式参数被声明而没有传入值时, 未传值的形式参数值为nil


function f(a, b, c)

    print(a, b, c)

end

f(114514, 1919810) -- 输出 114514	1919810	nil
  • 返回值

默认情况下, 函数返回值为nil


function f()

    -- 函数体

end

result = f()

print(result) -- 输出 nil

可以使用return语句来返回值


function f(a, b)

    return a

end

result = f(1, 2)

print(result) -- 输出 1

return语句也可以返回多个值


function f(a, b)

    return a, b

end

print(f(1, 2)) -- 输出 1	2

-- 可以配合多重赋值语句使用

local i, j = f(1, 2)

print(i) -- 输出 1

print(j) -- 输出 2

五、分支判断语句

在Lua中的分支判断语句由if关键字开始判断语句, 在than关键字处结束判断语句, 并开始一段代码块, 用else关键字开始另一分支代码块, 最后用end关键字结束整个语句, 具体如下:


a = 1

b = 2

if a==b then

    print("foo")

else

    print("no")

end

-- 输出 no

使用elseif <布尔表达式> then语句来开始另一个条件分支代码块


a = 1

b = 2

if a==b then

    print("foo")

elseif b > a then

    print("bar")

else

    print("no")

end

-- 输出 bar

注意elseif语句中, else和if不可分开写, 否则将会视为一个新的if语句而导致编译报错

六、循环语句

在Lua中拥有三种循环语句, 分别使用 for、while 和 repeat 关键字

for循环

for循环使用for关键字作为起始, 然后接受一个循环范围表达式, 类似i = 1, 10 表示从1到10, 然后在 do 关键字之后开始循环代码块, 最后用end关键字结束代码块


-- 这是一个最简单的循环

for i=1,10 do

    print(i) -- 输出0 1 2 3 4 5 6 7 8 9 10

end

-- 此处的i为局部变量, 离开for代码块后将没有定义

print(i) -- 输出nil

循环范围表达式可以加入第三个值来代表i所增加的步长


for i=1,10,2 do

    print(i) -- 输出 1 3 5 7 9

end

步长值可以是负数, 此时每次循环使得i减少对应步长值, 此时对应的i值应大于结束值, 否则代码块不会被执行


for i=10,1,-1 do

    print(i) -- 输出 10 9 8 7 6 5 4 3 2 1

end

循环过程中, i的值不能被更改, 若在循环代码块中对i值进行修改, 则得到的是一个新的i


for i=10,1,-1 do

    print(i) -- 输出 10 9 8 7 6 5 4 3 2 1

    i = 1

end

循环过程中, 使用break关键字提前退出循环


for i=10,1,-1 do

    print(i) -- 输出 10 9 8

    if i == 8 then break end

end

while循环

while循环类似for循环表达式, 但是将循环范围的表达式换成了布尔表达式, 当布尔表达式成真时, 执行循环代码块中的语句.


local x = 10

while x > 0 do

    print(x) -- 输出 10 9 8 7 6 5 4 3 2 1

    x = x - 1

end