Lua 初级教程

Lua 初级教程

  • Lua
  • [Lua 数据类型](#Lua 数据类型)
  • 变量
  • [Lua 循环](#Lua 循环)
    • [while 循环](#while 循环)
    • [for 循环](#for 循环)
    • [repeat...until 循环](#repeat...until 循环)
    • 循环嵌套
    • [break 语句](#break 语句)
  • [if...else 语句](#if...else 语句)
  • 函数
  • [Lua 数组](#Lua 数组)
  • [Lua 模块与包](#Lua 模块与包)

IDEA运行lua脚本

Lua

lua 是一种轻量小巧的脚本语言,用标准C语言编写并以源代码形式开放, 其设计目的是为了嵌入应用程序中,从而为应用程序提供灵活的扩展和定制功能。

Lua 数据类型

Lua 是动态类型语言,变量不要类型定义,只需要为变量赋值。 值可以存储在变量中,作为参数传递或结果返回。

Lua 中有 8 个基本类型分别为:nil、boolean、number、string、userdata、function、thread 和 table。

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

可以使用 type 函数测试给定变量或者值的类型:

lua 复制代码
print(type("Hello world"))      --> string
print(type(10.4*3))             --> number
print(type(print))              --> function
print(type(type))               --> function
print(type(true))               --> boolean
print(type(nil))                --> nil
print(type(type(nil)))          --> string
print(type(type(X)))            --> string

nil(空)

nil 类型表示一种没有任何有效值,它只有一个值 -- nil,例如打印一个没有赋值的变量,便会输出一个 nil 值。对于全局变量和 table,nil 还有一个"删除"作用,给全局变量或者 table 表里的变量赋一个 nil 值,等同于把它们删掉。

boolean(布尔)

boolean 类型只有两个可选值:true(真) 和 false(假),Lua 把 false 和 nil 看作是 false,其他的都为 true,数字 0 也是 true。

number(数字)

对于数字,Lua 默认只有一种 number 类型。例如 2,2.2,0.2,2.35e+8,0.2e-1,7.8263692594256e-06 这些都是number类型。

string(字符串)

字符串由一对双引号或单引号来表示。也可以用 2 个方括号 "[[]]" 来表示"一块"字符串。

lua 复制代码
str = [[
this is a string
  this is a string
]]
print(str)

>>>输出结果
this is a string
  this is a string

在对一个数字字符串上进行算术操作时,Lua 会尝试将这个数字字符串转成一个数字。字符串连接使用的是两个小数点。

lua 复制代码
print("2" + 6)      --> 8
print("2" + "6")    --> 8
print("2 + 6")      --> 2 + 6
print("-2e2" * "6") --> -1200
print("error" + 1)  --> 报错
print("error" .. 1)    --> error1
print("error" .. "1")  --> error1
print(1 .. 1)          --> 11
print("1" .. "1")      --> 11

使用 # 来计算字符串的长度,放在字符串前面。(补充一下,注释代码用两个减号,不能用井号和双斜杠)

lua 复制代码
a = "abcdefg"
print(#a)      --> 7
print(#"xyz")  --> 3

table(表)

在 Lua 里,table 的创建是通过"构造表达式"来完成,最简单构造表达式是{},用来创建一个空表。也可以在表里添加一些数据,直接初始化表。

Lua 中的表(table)其实是一个"关联数组"(associative arrays),数组的索引可以是数字或者是字符串。

table 不会固定长度大小,有新数据添加时 table 长度会自动增长,没初始的 table 都是 nil。

lua 复制代码
-- 创建一个空的 table
local tbl1 = {}
-- 直接初始表
local tbl = {"apple", "orange", "grape"}

print(tbl1)
print(tbl)

tbl[-1] = "National"
tbl[1] = nil
tbl[2] = "Tomato"
tbl["key1"] = "value1"

print(#tbl)
print("============")
for k, v in pairs(tbl1) do
    print(k .. " : " .. v)
end
print("============")
for k, v in pairs(tbl) do
    print(k .. " : " .. v)
end

>>>输出结果
table: 00C99200
table: 00C99700
0
============
============
3 : grape
2 : Tomato
-1 : National
key1 : value1

function(函数)

在 Lua 中,函数是被看作是"第一类值(First-Class Value)",函数可以存在变量里。

lua 复制代码
-- function_test.lua 脚本文件
function factorial1(n)
    if n == 0 then
        return 1
    else
        return n * factorial1(n - 1)
    end
end
print(factorial1(5))
factorial2 = factorial1
print(factorial2(5))

>>>输出结果
120
120

function 可以以匿名函数(anonymous function)的方式通过参数传递。

lua 复制代码
-- function_test2.lua 脚本文件
function testFun(tab,fun)
    for k ,v in pairs(tab) do
            print(fun(k,v))
    end
end


tab={key1="val1",key2="val2"};
testFun(tab,
function(key,val)--匿名函数
   return key.."="..val;
end
)

>>>输出结果
key1=val1
key2=val2

thread(线程)

在 Lua 里,最主要的线程是协同程序(coroutine)。它跟线程(thread)差不多,拥有自己独立的栈、局部变量和指令指针,可以跟其他协同程序共享全局变量和其他大部分东西。

线程跟协程的区别:线程可以同时多个运行,而协程任意时刻只能运行一个,并且处于运行状态的协程只有被挂起(suspend)时才会暂停。

userdata(自定义类型)

userdata 是一种用户自定义数据,用于表示一种由应用程序或 C/C++ 语言库所创建的类型,可以将任意 C/C++ 的任意数据类型的数据(通常是 struct 和 指针)存储到 Lua 变量中调用。

变量

应该尽可能的使用局部变量,有两个好处:

  1. 避免命名冲突。
  2. 访问局部变量的速度比全局变量更快。
lua 复制代码
-- test.lua 文件脚本
a = 5               -- 全局变量
local b = 5         -- 局部变量

function joke()
    c = 5           -- 全局变量
    local d = 6     -- 局部变量
    print(a, b, c, d) --> 5 5 5 6
end

joke()
print(c,d)          --> 5 nil
print(a, b, c, d)   --> 5 5 5 nil

do
    local a = 6     -- 局部变量
    b = 6           -- 对局部变量重新赋值
    print(a,b);     --> 6 6
end

print(a,b)      --> 5 6

Lua 可以对多个变量同时赋值,变量列表和值列表的各个元素用逗号分开,赋值语句右边的值会依次赋给左边的变量。

赋值语句Lua会先计算右边所有的值然后再执行赋值操作,所以我们可以不引入第三变量就能对变量的值进行交换。

lua 复制代码
a, b = 10, 20       --> 等价于       a=10; b=20

x, y = y, x                     -- swap 'x' for 'y'
a[i], a[j] = a[j], a[i]         -- swap 'a[i]' for 'a[j]'

赋值的时候,等号两边的元素数量不匹配

lua 复制代码
a, b, c = 0, 1
print(a,b,c)             --> 0   1   nil

a, b = 3, 4, 5
print(a,b)               --> 3   4

a, b, c = 0
print(a,b,c)             --> 0   nil   nil

a, b, c = 0, 0, 0
print(a,b,c)             --> 0   0   0

Lua 循环

while 循环

lua 复制代码
-- 输出10到19
a=10
while( a < 20 )
do
    print(a)
    a = a+1
end

for 循环

lua 复制代码
-- 输出-10到10(一共21个数)
for i=-10,10 do
    print(i)
end

-- 输出 -10到10之间的偶数(一共11个数)
for i=-10,10,2 do
    print(i)
end

-- 输出10到1
for i=10,1,-1 do
    print(i)
end

-- 不进入循环体,所以不打印数字111
for i=1,10,-1 do
    print(111)
end

i是数组索引值,v是对应索引的数组元素值。ipairs是Lua提供的一个迭代器函数,用来迭代数组

lua 复制代码
a = {key1 = "value1", key2 = "value2", key3 = "value3"}
-- 打印表a的键和值
for k, v in pairs(a) do
    print(k, v)
end

b = {"apple", "banana", "orange"}
-- 打印数组b的索引和值
for i, v in pairs(b) do
    print(i, v)
end

-- 下面的写法会报错
for i in a do
    print(i)
end

repeat...until 循环

repeat...until 循环语句不同于 for 和 while循环,for 和 while 循环的条件语句在当前循环执行开始时判断,而 repeat...until 循环的条件语句在当前循环结束后判断。

lua 复制代码
repeat
   statements
until( condition )

循环条件判断语句(condition)在循环体末尾部分,所以在条件进行判断前循环体都会执行一次。

如果条件判断语句(condition)为 false,循环会重新开始执行,直到条件判断语句(condition)为 true 才会停止执行。

lua 复制代码
-- 输出10到15(如果交换循环体里的两行代码,打印结果为11到16)
a = 10
repeat
    print(a)
    a = a + 1
until( a > 15 )

结构与do while 循环类似。不管条件如何都会进入循环体一次。不同的是,当until 的条件判断为 true 时会停止执行。

循环嵌套

lua 复制代码
-- 打印九九乘法表
for i = 1,9
do
    local line = ""
    for j = 1,i
    do
        line = line .. " ".. (j.."x"..i.."="..i*j)
    end
    print(line)
end

break 语句

break 语句插入在循环体中,用于退出当前循环或语句。

如果使用循环嵌套,break语句将停止最内层循环的执行,并开始执行外层的循环语句。

lua 复制代码
-- 输出1到5
for i = 1,10 do
    print(i)
    if (i == 5) then
        break
    end
end

if...else 语句

lua 复制代码
a = 50
if (a == 10) then
    print("a 的值为 10")
elseif (a == 20) then
    print("a 的值为 20")
elseif (a == 30) then
    print("a 的值为 30")
else
    print("没有匹配 a 的值")
end
print("a 的真实值为: ", a)

>>>输出结果
没有匹配 a 的值
a 的真实值为: 	50

lua中不支持switch-case语句,我们可以使用if elseif来代替

lua 复制代码
a = "Sunday"
if (a == "Monday") then
    print("星期一")
elseif (a == "Tuesday") then
    print("星期二")
elseif (a == "Wednesday") then
    print("星期三")
elseif (a == "Thursday") then
    print("星期四")
else
    print("休息日")
end

函数

多个入参

lua 复制代码
-- 函数返回两个值的最大值
function max(num1, num2)
   if (num1 > num2) then
      result = num1;
   else
      result = num2;
   end
   return result; 
end

-- 对所有参数求和
function add(...)
    local sum = 0;
    local args = {...}  -- 将所有参数收集到一个表里
    for i, v in ipairs(args) do
        sum = sum + v
    end
    return sum
end

多参数的循环也可以这么写 for i, v in ipairs{...}

多返回值

lua 复制代码
function maximum (a)
    local mi = 1             -- 最大值索引
    local m = a[mi]          -- 最大值
    for i,val in ipairs(a) do
        if val > m then
            mi = i
            m = val
        end
    end
    return m, mi
end
index, num = maximum({8,10,23,12,5});

通常在遍历变长参数的时候只需要使用 {...},然而变长参数可能会包含一些 nil,那么就可以用 select 函数来访问变长参数了:select('#', ...) 或者 select(n, ...)

select('#', ...) 返回可变参数的长度。

select(n, ...) 用于返回从起点 n 开始到结束位置的所有参数列表。

调用 select 时,必须传入一个固定实参 selector(选择开关) 和一系列变长参数。如果 select为数字 n,那么 select 返回参数列表中从索引 n 开始到结束位置的所有参数列表,否则只能为字符串 #,这样 select 返回变长参数的总数。

lua 复制代码
function myFun (...)
    a = {...}
    print(#a)  --> 6
    b = select(2,...)  --函数返回一个列表。因为左侧变量只有一个,所以会将列表第一个值赋值给变量
    print (b)  --> 10
    print(select("#", ...))    --> 6
    print(select("3", ...))    --> nil	7	3	5
    print(select(3, ...))      --> nil	7	3	5
end
myFun(8,10,nil,7,3,5);

Lua 数组

lua 索引默认从 1 开始。使用整数索引来访问数组元素,如果指定的索引没有值则返回 nil。除此外还可以以负数为数组索引值

lua 复制代码
-- 创建一个数组
local myArray = {10, 20, 30, 40, 50}
-- 循环遍历数组
for i = -1, #myArray do
    print(myArray[i])
end

>>>输出结果
nil
nil
10
20
30
40
50
lua 复制代码
-- 将 -2 到 2 之间的五个整数,添加到数组中
array = {}
for i= -2, 2 do
   array[i] = i
end

数组的增删改

lua 复制代码
-- 创建一个数组
local myArray = {10, 20, 30, 40, 50}

-- 添加新元素到数组末尾
myArray[#myArray + 1] = 60

-- 修改数组元素(将20修改为25)
myArray[2] = 25

-- 删除第三个元素(将30删除)
table.remove(myArray, 3)

二维数组

lua 复制代码
-- 依次将1到9写入数组中
array = {}
for i=1,3 do
    array[i] = {}
    for j=1,3 do
        array[i][j] = 3*(i-1)+j
    end
end

Table 函数

concat 拼接

lua 复制代码
local myArray = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri"}
print(table.concat(myArray))   --> SunMonTueWedThuFri
print(table.concat(myArray, "-"))  --> Sun-Mon-Tue-Wed-Thu-Fri
print(table.concat(myArray, "-", 3)) --> Tue-Wed-Thu-Fri
print(table.concat(myArray,"-",1,5))  --> Sun-Mon-Tue-Wed-Thu

insert 插入

lua 复制代码
local myArray = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri"}
table.insert(myArray, "DayEnd")   --> 数组末尾添加元素 DayEnd
table.insert(myArray, 2, "Day2")   --> 数组第二个位置插入元素 Day2

remove 删除

lua 复制代码
local myArray = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri"}
print(table.remove(myArray))   --> 删除数组最后一个元素,并返回 Fri
print(table.remove(myArray, 3))   --> 删除数组第三个元素,并返回 Tue

Lua 模块与包

lua 复制代码
require("./utils/TimeUtil")

print(dateTime.year)
print(dateTime.name)
-- 函数有入参必须传,不写会报错。但如果函数没入参,参数传不传都可以
dateTime.fun1(2)
--dateTime.fun2()  fun2是私有函数,无法调用
dateTime.fun3()

>>>输出结果
2025
dateTime
函数1打印参数a:2
函数2打印

TimeUtil.lua 文件内容

lua 复制代码
-- 定义一个名为 dateTime 的模块
dateTime = {}
-- 定义两个常量
dateTime.year = 2025
dateTime.name = "dateTime"
-- 定义公有一个函数
function dateTime.fun1(a)
    print("函数1打印参数a:" .. a)
end
-- 定义私有一个函数
local function fun2()
    print("函数2打印")
end
-- 通过公有函数调用私有函数
function dateTime.fun3()
    fun2()
end

return dateTime

Lua 的模块是由变量、函数等已知元素组成的 table,因此创建一个模块很简单,就是创建一个 table,然后把需要导出的常量、函数放入其中,最后返回这个 table 就行。

模块的结构就是一个 table 的结构,因此可以像操作调用 table 里的元素那样来操作调用模块里的常量或函数。

上面的 func2 声明为程序块的局部变量,即表示一个私有函数,因此是不能从外部访问模块里的这个私有函数,必须通过模块里的公有函数来调用。

相关推荐
龙哥·三年风水3 天前
openresty(nginx)+lua+kafka实现日志搜集系统
kafka·lua·openresty
天堂的恶魔9465 天前
软件测试 —— Postman(全局变量和环境变量,请求前置脚本,关联)
测试工具·lua·postman
xiao-xiang10 天前
nginx-lua模块安装
运维·nginx·lua
利来利往10 天前
lua下标是可以从0开始
lua
qq_3564086611 天前
redis监控会不会统计lua里面执行的命令次数
redis·junit·lua
請叫我菜鳥11 天前
什么是 OpenResty
nginx·lua·openresty
我是單身你是狗11 天前
token
开发语言·lua
maply12 天前
如何编写和运行 Lua 脚本优化复杂的 Redis 操作
开发语言·数据库·redis·消息队列·lua
看星星的派大星12 天前
nvim , neovim , Lua 语法, text object
开发语言·lua