Lua 从基础入门到精通(非常详细)

news2024/11/24 16:41:52

目录

什么是 Lua?

Lua 环境安装

Lua基本语法

注释

数据类型

 nil(空)

Boolean

number(数字)

string(字符串)

function(函数)

userdata

thread

table(表)

流程控制

运算符

循环

详解string库

Lua 模块与包

案例实战


什么是 Lua?

        Lua 是一种轻量小巧的脚本语言,它用标准C语言编写并以源代码形式开放。这意味着什么呢?这意味着Lua虚拟机可以很方便的嵌入别的程序里,从而为应用程序提供灵活的扩展和定制功能。而整个Lua虚拟机编译后仅仅一百余K,经过适当的裁剪还能做到更小,十分适合嵌入式的开发。

Lua 官网:The Programming Language Lua

Lua 5.3 参考手册:Lua 5.3 参考手册 - 目录

Lua 在线调试工具:LuatOS 在线模拟 - lua在线测试


Lua 环境安装

可以不安装 Lua环境, 直接用在线调试就可以, 但也有一些学习需要安装,有需要的可以安装.

Linux 系统上安装

下载源码安装:

curl -L -R -O https://www.lua.org/ftp/lua-5.3.6.tar.gz
tar zxf lua-5.3.6.tar.gz
cd lua-5.3.6
make all test
make install

Window 系统上安装 Lua

window 下你可以使用一个叫 "SciTE" 的 IDE环 境来执行 lua 程序,下载地址为:

  • Github 下载地址:https://github.com/rjpcomputing/luaforwindows/releases

  • Google Code下载地址 : https://code.google.com/p/luaforwindows/downloads/list

双击安装后即可在该环境下编写 Lua 程序并运行。

或者

访问Lua Binaries Download 下载

把红圈内的东西,下载后解压到c:\lua(里面有dll文件重复了,取可执行文件包内的就行了)

c:\lua目录情况如下

 直接运行lua53.exe 就可以


Lua基本语法

以下大部分的 Lua 语句都在Lua在线调试工具上执行。

注释

单行注释

单行注释以两个连字符 -- 开头,后面跟随的内容将被解释器忽略。

--

单行注释通常用于对代码的简短解释或标记。

多行注释

多行注释以 --[[ 开始,并以 ]] 结束,适用于需要对大段代码进行说明的情况。

--[[
 多行注释
 多行注释
 --]]

 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表示执行的独立线路,用于执行协同程序
tableLua 中的表(table)其实是一个"关联数组"(associative arrays),数组的索引可以是数字、字符串或表类型。在 Lua 里,table 的创建是通过"构造表达式"来完成,最简单构造表达式是{},用来创建一个空表。
  •  nil(空)

Nil 是值 nil 的类型, 其主要特征就是和其它值区别开;通常用来表示一个有意义的值不存在时的状态。例如打印一个没有赋值的变量,便会输出一个 nil 值:

在lua在线测试 上执行命令

print(a)

运行结果


  • Boolean

Booleanfalsetrue 两个值的类型。 nilfalse 都会导致条件判断为假; 而其它任何值都表示为真,数字 0 也是 true。

print(type(true))
print(type(false))
print(type(nil))
 
if false or nil then
    print("至少有一个是 true")
else
    print("false 和 nil 都为 false")
end

if 0 then
    print("数字 0 是 true")
else
    print("数字 0 为 false")
end

 以上代码执行结果如下:

$ lua test.lua
boolean
boolean
nil
false 和 nil 都为 false
数字 0 是 true


  • number(数字)

Number 代表了整数和实数(浮点数),也就是double(双精度)类型。

print(type(2))
print(type(2.2))
print(type(0.2))
print(type(2e+1))
print(type(0.2e-1))
print(type(7.8263692594256e-06))

以上代码执行结果:

number
number
number
number
number
number

  • string(字符串)

 字符串(即string),就是一串文本数据,可以存储你要的文本。

Lua 语言中字符串可以使用以下三种方式来表示:

  1. 单引号间的一串字符

  2. 双引号间的一串字符

  3. [[和]]间的一串字符

string1 = "this is string1"
string2 = 'this is string2'

str4 = [[使用双括号时,甚至能包含换行数据
换行了
最后一行]]

print(string1)
print(string2)
print(str4)

 以上代码执行结果:

this is string1
this is string2
使用双括号时,甚至能包含换行数据
换行了
最后一行


  • function(函数)

在Lua中,函数是对语句和表达式进行抽象的主要方法。既可以用来处理一些特殊的工作,也可以用来计算一些值。

Lua 提供了许多的内建函数,你可以很方便的在程序中调用它们,如print()函数可以将传入的参数打印在控制台上。

Lua 函数主要有两种用途:

  • 1.完成指定的任务,这种情况下函数作为调用语句使用;
  • 2.计算并返回值,这种情况下函数作为赋值语句的表达式使用。

函数定义

Lua 编程语言函数定义格式如下:

optional_function_scope function function_name( argument1, argument2, argument3..., argumentn)
    function_body
    return result_params_comma_separated
end

解析:

  • optional_function_scope: 该参数是可选的指定函数是全局函数还是局部函数,未设置该参数默认为全局函数,如果你需要设置函数为局部函数需要使用关键字 local,通常不设置。

  • function_name: 指定函数名称。

  • argument1, argument2, argument3..., argumentn: 函数参数,多个参数以逗号隔开,函数也可以不带参数。

  • function_body: 函数体,函数中需要执行的代码语句块。

  • result_params_comma_separated: 函数返回值,Lua语言函数可以返回多个值,每个值以逗号隔开。

定义如下:

function hello()
    print('Hello world!')
end


-- 调用函数
hello()

定义传参,只需写参数名称,不需要写参数类型,比如:argument1, argument2

function hello(argument1, argument2)
    print('Hello world!',argument1, argument2)
end


-- 调用函数
hello('参数1', '参数2')

定义函数返回值,如果多个返回值,则以逗号隔开,然后接受变量多个

function hello(argument1, argument2)
    print('Hello world!',argument1, argument2)
  return argument1,argument2
end

-- 调用函数
val1,val2=hello('参数1', '参数2')
print(val1,val2)

可变参数

Lua 函数可以接受可变数目的参数,和 C 语言类似,在函数参数列表中使用三点 ... 表示函数有可变的参数。

function hello(...)
    local arg={...}
    return arg
end

-- 调用函数
arr=hello('参数1', '参数2','参数3')
print(arr[1],arr[2],arr[3])

  • userdata

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

用户数据类型的值是一个内存块, 有两种用户数据: 完全用户数据 ,指一块由 Lua 管理的内存对应的对象; 轻量用户数据 ,则指一个简单的 C 指针。 用户数据在 Lua 中除了赋值与相等性判断之外没有其他预定义的操作。


  • thread

thread 类型表示了一个独立的执行序列,被用于实现协程 。 Lua 的线程与操作系统的线程毫无关系。 Lua 为所有的系统,包括那些不支持原生线程的系统,提供了协程支持。

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

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

基本语法

协同程序由 coroutine 模块提供支持。

使用协同程序,你可以在函数中使用 coroutine.create 创建一个新的协同程序对象,并使用 coroutine.resume 启动它的执行。协同程序可以通过调用 coroutine.yield 来主动暂停自己的执行,并将控制权交还给调用者。

方法描述
coroutine.create()创建 coroutine,返回 coroutine, 参数是一个函数,当和 resume 配合使用的时候就唤醒函数调用
coroutine.resume()重启 coroutine,和 create 配合使用
coroutine.yield()挂起 coroutine,将 coroutine 设置为挂起状态,这个和 resume 配合使用能有很多有用的效果
coroutine.status()查看 coroutine 的状态
注:coroutine 的状态有三种:dead,suspended,running,具体什么时候有这样的状态请参考下面的程序
coroutine.wrap()创建 coroutine,返回一个函数,一旦你调用这个函数,就进入 coroutine,和 create 功能重复
coroutine.running()返回正在跑的 coroutine,一个 coroutine 就是一个线程,当使用running的时候,就是返回一个 coroutine 的线程号

以下实例演示了如何使用 Lua 协同程序:

function foo()
    print("协同程序 foo 开始执行")
    local value = coroutine.yield("暂停 foo 的执行")
    print("协同程序 foo 恢复执行,传入的值为: " .. tostring(value))
    print("协同程序 foo 结束执行")
end

-- 创建协同程序
local co = coroutine.create(foo)

-- 启动协同程序
local status, result = coroutine.resume(co)
print(result) -- 输出: 暂停 foo 的执行

-- 恢复协同程序的执行,并传入一个值
status, result = coroutine.resume(co, 42)
print(result) -- 输出: 协同程序 foo 恢复执行,传入的值为: 42

以上实例中,我们定义了一个名为 foo 的函数作为协同程序。在函数中,我们使用 coroutine.yield 暂停了协同程序的执行,并返回了一个值

。在主程序中,我们使用 coroutine.create 创建了一个协同程序对象,并使用 coroutine.resume 启动了它的执行。

在第一次调用 coroutine.resume 后,协同程序执行到 coroutine.yield 处暂停,并将值返回给主程序。然后,我们再次调用 coroutine.resume,并传入一个值作为协同程序恢复执行时的参数。

执行以上代码输出结果为:

协同程序 foo 开始执行
暂停 foo 的执行
协同程序 foo 恢复执行,传入的值为: 42
协同程序 foo 结束执行
nil

  • table(表)

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

-- 创建一个空的 table
local tbl1 = {}
 
-- 直接初始表
local tbl2 = {"apple", "pear", "orange", "grape"}

我们甚至能在里面放function变量

t = {
    function() return 123 end,
    function() print("abc") end,
    function(a,b) return a+b end,
    function() print("hello world") end,
}
t[1]()
t[2]()
t[3](1,2)
t[4]()

这些table访问每个元素的方式仍然是直接用下标,并且也能用下标来进行修改。

下标也可以直接在声明时进行指定,像下面这样:

t = {6,7,8,9}
--上面和下面的代码等价
t = {
    [1] = 6,
    [2] = 7,
    [3] = 8,
    [4] = 9,
}

--甚至你可以跳过某些下标
t = {
    [1] = 6,
    [3] = 7,
    [5] = 8,
    [7] = 9,
}
print(t[7])
--输出9

--在声明后赋予元素值也是可以的
t = {}--空的table
t[101] = 10
print(t[101])
--输出10

在Lua中,下标也可以是字符串,如下面的例子

t = {
    ["apple"] = 10,
    banana = 12,
    pear = 6,
}
--使用["下标"] = 值
--和  下标 = 值
--都是正确写法
--当第二种方式有歧义时,应该用第一种方式

--可以用下面两种方式访问:
print(t["apple"])
--输出10
print(t.apple)
--输出10
--当第二种方式有歧义时,应该用第一种方式

table中,可以直接用table名[下标]table名.string下标来访问元素。实际上,在Lua中,所有的全局变量全部被存放在了一个大table中,这个table名为:_G

n = 123--新建变量
print(n)--输出123
print(_G.n)--输出123

_G.abc = 1--相当于新建全局变量
print(abc)--输出1

_G["def"] = 23--相当于新建全局变量
print(def)--输出23

--甚至你可以像下面这样
_G.print("hello")
_G["print"]("world")

Table 操作

以下列出了 Table 操作常用的方法:

序号方法 & 用途
1table.concat (table [, sep [, start [, end]]]):

concat是concatenate(连锁, 连接)的缩写. table.concat()函数列出参数中指定table的数组部分从start位置到end位置的所有元素, 元素间以指定的分隔符(sep)隔开。

2table.insert (table, [pos,] value):

在table的数组部分指定位置(pos)插入值为value的一个元素. pos参数可选, 默认为数组部分末尾.

3table.maxn (table)

指定table中所有正数key值中最大的key值. 如果不存在key值为正数的元素, 则返回0。(Lua5.2之后该方法已经不存在了,本文使用了自定义函数实现)

4table.remove (table [, pos])

返回table数组部分位于pos位置的元素. 其后的元素会被前移. pos参数可选, 默认为table长度, 即从最后一个元素删起。

5table.sort (table [, comp])

对给定的table进行升序排序。

Table 连接

我们可以使用 concat() 输出一个列表中元素连接成的字符串:

实例

fruits = {"banana","orange","apple"}
-- 返回 table 连接后的字符串
print("连接后的字符串 ",table.concat(fruits))

-- 指定连接字符
print("连接后的字符串 ",table.concat(fruits,", "))

-- 指定索引来连接 table
print("连接后的字符串 ",table.concat(fruits,", ", 2,3))

执行以上代码输出结果为:

连接后的字符串     bananaorangeapple
连接后的字符串     banana, orange, apple
连接后的字符串     orange, apple

插入和移除

以下实例演示了 table 的插入和移除操作:

实例

fruits = {"banana","orange","apple"}

-- 在末尾插入
table.insert(fruits,"mango")
print("索引为 4 的元素为 ",fruits[4])

-- 在索引为 2 的键处插入
table.insert(fruits,2,"grapes")
print("索引为 2 的元素为 ",fruits[2])

print("最后一个元素为 ",fruits[5])
table.remove(fruits)
print("移除后最后一个元素为 ",fruits[5])

执行以上代码输出结果为:

索引为 4 的元素为     mango
索引为 2 的元素为     grapes
最后一个元素为     mango
移除后最后一个元素为     nil

Table 排序

以下实例演示了 sort() 方法的使用,用于对 Table 进行排序:

实例

fruits = {"banana","orange","apple","grapes"}
print("排序前")
for k,v in ipairs(fruits) do
        print(k,v)
end

table.sort(fruits)
print("排序后")
for k,v in ipairs(fruits) do
        print(k,v)
end

执行以上代码输出结果为:

排序前
1    banana
2    orange
3    apple
4    grapes
排序后
1    apple
2    banana
3    grapes
4    orange

Table 最大值

table.maxn 在 Lua5.2 之后该方法已经不存在了,我们定义了 table_maxn 方法来实现。

以下实例演示了如何获取 table 中的最大值:

实例

function table_maxn(t)
  local mn=nil;
  for k, v in pairs(t) do
    if(mn==nil) then
      mn=v
    end
    if mn < v then
      mn = v
    end
  end
  return mn
end
tbl = {[1] = 2, [2] = 6, [3] = 34, [26] =5}
print("tbl 最大值:", table_maxn(tbl))
print("tbl 长度 ", #tbl)

执行以上代码输出结果为:

tbl 最大值:    34
tbl 长度     3

注意:

当我们获取 table 的长度的时候无论是使用 # 还是 table.getn 其都会在索引中断的地方停止计数,而导致无法正确取得 table 的长度。

可以使用以下方法来代替:

function table_leng(t)
  local leng=0
  for k, v in pairs(t) do
    leng=leng+1
  end
  return leng;
end

流程控制

Lua 提供了以下控制结构语句:

语句描述
if 语句if 语句 由一个布尔表达式作为条件判断,其后紧跟其他语句组成。
if...else 语句if 语句 可以与 else 语句搭配使用, 在 if 条件表达式为 false 时执行 else 语句代码。
if 嵌套语句你可以在ifelse if中使用一个或多个 ifelse if 语句 。

 单条件判断

if 条件 then
    符合条件的代码
end

实例

n = 5
if n < 10 then
    print('n小于10')
end

多条件判断

if 条件1 then
    满足条件1
elseif 条件2 then
    不满足条件1,但是满足条件2
else
    前面条件全都不满足
end

实例

n = 1--更改这个数多运行几次试试
if n >= 0 and n < 5 then
    print('太小')
elseif n >= 5 and n < 10 then
    print('适中')
elseif n >= 10 then
    print('太大')
end

运算符

运算符是一个特殊的符号,用于告诉解释器执行特定的数学或逻辑运算。Lua提供了以下几种运算符类型:

  • 算术运算符
  • 关系运算符
  • 逻辑运算符
  • 其他运算符

算术运算符

下表列出了 Lua 语言中的常用算术运算符,设定 A 的值为10,B 的值为 20:

操作符描述实例
+加法A + B 输出结果 30
-减法A - B 输出结果 -10
*乘法A * B 输出结果 200
/除法B / A 输出结果 2
%取余B % A 输出结果 0
^乘幂A^2 输出结果 100
-负号-A 输出结果 -10
//整除运算符(>=lua5.3)5//2 输出结果 2

实例

我们可以通过以下实例来更加透彻的理解算术运算符的应用:

实例

a = 21
b = 10
c = a + b
print("Line 1 - c 的值为 ", c )
c = a - b
print("Line 2 - c 的值为 ", c )
c = a * b
print("Line 3 - c 的值为 ", c )
c = a / b
print("Line 4 - c 的值为 ", c )
c = a % b
print("Line 5 - c 的值为 ", c )
c = a^2
print("Line 6 - c 的值为 ", c )
c = -a
print("Line 7 - c 的值为 ", c )

以上程序执行结果为:

Line 1 - c 的值为     31
Line 2 - c 的值为     11
Line 3 - c 的值为     210
Line 4 - c 的值为     2.1
Line 5 - c 的值为     1
Line 6 - c 的值为     441
Line 7 - c 的值为     -21

关系运算符

下表列出了 Lua 语言中的常用关系运算符,设定 A 的值为21,B 的值为 10:

操作符描述实例
==等于,检测两个值是否相等,相等返回 true,否则返回 false(A == B) 为 false。
~=不等于,检测两个值是否相等,不相等返回 true,否则返回 false(A ~= B) 为 true。
>大于,如果左边的值大于右边的值,返回 true,否则返回 false(A > B) 为 false。
<小于,如果左边的值大于右边的值,返回 false,否则返回 true(A < B) 为 true。
>=大于等于,如果左边的值大于等于右边的值,返回 true,否则返回 false(A >= B) 返回 false。
<=小于等于, 如果左边的值小于等于右边的值,返回 true,否则返回 false(A <= B) 返回 true。

实例

a = 21
b = 10
print('==的结果',a==b)
print('~=的结果',a~=b)
print('>的结果',a>b)
print('<的结果',a<b)
print('>=的结果',a>=b)
print('<=的结果',a<=b)

执行以上代码输出结果为:

 ==的结果  false

 ~=的结果  true

 >的结果   true

 <的结果   false

 >=的结果  true

 <=的结果  false

逻辑运算符

逻辑运算符基于布尔型的值来进行计算,并给出结果,下表列出了 Lua 语言中的常用逻辑运算符:

符号

含义

and

逻辑与操作符。 若 A 为 false,则返回 A,否则返回 B

or

逻辑或操作符。 若 A 为 true,则返回 A,否则返回 B

not

逻辑非操作符。与逻辑运算结果相反,如果条件为 true,逻辑非为 false

实例

print('true and false的结果',true and false)
print('true or false的结果',true or false)
print('true and true的结果',true and true)
print('false or false的结果',false or false)
print('not false的结果',not false)
print('123 and 345的结果',123 and 345)
print('nil and true的结果',nil and true)

 执行以上代码输出结果为:

true and false的结果   false
true or false的结果    true
true and true的结果    true
false or false的结果   false
not false的结果    true
123 and 345的结果  345
nil and true的结果 nil

其他运算符

下表列出了 Lua 语言中的连接运算符与计算表或字符串长度的运算符:

操作符描述实例
..连接两个字符串a..b ,其中 a 为 "Hello " , b 为 "World", 输出结果为 "Hello World"。
#一元运算符,返回字符串或表的长度。#"Hello" 返回 5

实例

我们可以通过以下实例来更加透彻的理解连接运算符与计算表或字符串长度的运算符的应用:

实例

a = "Hello "
b = "World"

print("连接字符串 a 和 b ", a..b )

print("b 字符串长度 ",#b )

print("字符串 Test 长度 ",#"Test" )

print("菜鸟教程网址长度 ",#"www.runoob.com" )

以上程序执行结果为:

连接字符串 a 和 b     Hello World
b 字符串长度     5
字符串 Test 长度     4
菜鸟教程网址长度     14

循环

在实际功能实现中,经常会遇到需要循环运行的代码,比如从1到100填充table数据,我们可以直接用循环语句来实现

Lua 语言提供了以下几种循环处理方式:

循环类型描述
while 循环在条件为 true 时,让程序重复地执行某些语句。执行语句前会先检查条件是否为 true。
for 循环重复执行指定语句,重复次数可在 for 语句中控制。
repeat...until重复执行循环,直到 指定的条件为真时为止
循环嵌套可以在循环内嵌套一个或多个循环语句(while do ... end;for ... do ... end;repeat ... until;)

while 循环

while这个循环语法,整体的格式如下:

while 继续循环判断依据 do
    执行的代码
end

实例

local result = 0
local num = 1

while num <= 100 do
    result = result + num
    num = num + 1
end

print(result)

for 循环

for这个循环语法,整体的格式如下:

for 临时变量名=开始值,结束值,步长 do
    循环的代码
end

其中,步长可以省略,默认为1

临时变量名可以直接在代码区域使用(但不可更改),每次循环会自动加步长值,并且在到达结束值后停止循环. 如果需要倒序, 则步长设置为负数就可以,比如-1,代表每次减一.

实例

local result = 0

for i=1,100 do
    result = result + i
end

print(result)

中断循环

        如果想跳出 while 或者 for 循环,则可以使用 break 关键字, 代码如下

result = 0
for i=1,100 do
    result = result + i
    if result > 100 then
        result = result - i
        break
    end
end

print(result)

for 迭代器

在 Lua 中迭代器是一种支持指针类型的结构,它可以遍历集合的每一个元素。

泛型 for 迭代器提供了集合的 key/value 对,语法格式如下:

for k, v in pairs(t) do
    print(k, v)
end

上面代码中,k, v为变量列表;pairs(t)为表达式列表。

查看以下实例:

实例

array = {"Google", "Runoob"}

for key,value in ipairs(array)
do
   print(key, value)
end

以上代码执行输出结果为:

1  Google
2  Runoob

详解string库

 Lua 提供了很多字符串操作 api,方便我们对字符串的操作,接下来讲解string库的各种接口.

序号方法 & 用途
1

string.upper(argument):
字符串全部转为大写字母。

> print(string.upper('abcd'))

ABCD

2

string.lower(argument):
字符串全部转为小写字母。

> print(string.upper('ABCD'))

abcd

3string.gsub(mainString,findString,replaceString,num)

在字符串中替换。

mainString 为要操作的字符串, findString 为被替换的字符,replaceString 要替换的字符,num 替换次数(可以忽略,则全部替换),如:
> string.gsub("aaaa","a","z",3);
zzza    3
4string.find (str, substr, [init, [plain]])

在一个指定的目标字符串 str 中搜索指定的内容 substr,如果找到了一个匹配的子串,就会返回这个子串的起始索引和结束索引,不存在则返回 nil。

init 指定了搜索的起始位置,默认为 1,可以一个负数,表示从后往前数的字符个数。

plain 表示是否使用简单模式,默认为 false,true 只做简单的查找子串的操作,false 表示使用使用正则模式匹配。

以下实例查找字符串 "Lua" 的起始索引和结束索引位置:

> string.find("Hello Lua user", "Lua", 1) 
7    9
5string.reverse(arg)
字符串反转
> string.reverse("Lua")
auL
6string.format(...)
返回一个类似printf的格式化字符串
> string.format("the value is:%d",4)
the value is:4
7string.char(arg) 和 string.byte(arg[,int])
char 将整型数字转成字符并连接, byte 转换字符为整数值(可以指定某个字符,默认第一个字符)。
> string.char(97,98,99,100)
abcd
> string.byte("ABCD",4)
68
> string.byte("ABCD")
65
8string.len(arg)
计算字符串长度。
string.len("abc")
3
9string.rep(string, n)
返回字符串string的n个拷贝
> string.rep("abcd",2)
abcdabcd
10..
链接两个字符串
> print("www.runoob.".."com")
www.runoob.com
11string.gmatch(str, pattern)
返回一个迭代器函数,每一次调用这个函数,返回一个在字符串 str 找到的下一个符合 pattern 描述的子串。如果参数 pattern 描述的字符串没有找到,迭代函数返回nil。
> for word in string.gmatch("Hello Lua user", "%a+") do print(word) end
Hello
Lua
user
12string.match(str, pattern, init)
string.match()只寻找源字串str中的第一个配对. 参数init可选, 指定搜寻过程的起点, 默认为1。
在成功配对时, 函数将返回配对表达式中的所有捕获结果; 如果没有设置捕获标记, 则返回整个配对字符串. 当没有成功的配对时, 返回nil。
> = string.match("I have 2 questions for you.", "%d+ %a+")
2 questions

> = string.format("%d, %q", string.match("I have 2 questions for you.", "(%d+) (%a+)"))
2, "questions"
13
string.sub(s, i [, j])
string.sub() 用于截取字符串.返回字符串 s 中,从索引 i 到索引 j 之间的子字符串。i 可以为负数,表示倒数第几个字符。当 j 缺省时,默认为 -1,也就是字符串 s 的最后位置。当索引 i 在字符串 s 的位置在索引 j 的后面时,将返回一个空字符串。

>print(string.sub('abcdcef',2,5))

bcdc


Lua 模块与包

模块类似于一个封装库,从 Lua 5.1 开始,Lua 加入了标准的模块管理机制,可以把一些公用的代码放在一个文件里,以 API 接口的形式在其他地方调用,有利于代码的重用和降低代码耦合度。

Lua 的模块是由变量、函数等已知元素组成的 table,因此创建一个模块很简单,就是创建一个 table,然后把需要导出的常量、函数放入其中,最后返回这个 table 就行。以下为创建自定义模块 module.lua,文件代码格式如下:

-- 文件名为 module.lua
-- 定义一个名为 module 的模块
module = {}
 
-- 定义一个常量
module.constant = "这是一个常量"
 
-- 定义一个函数
function module.func1()
    io.write("这是一个公有函数!\n")
end
 
local function func2()
    print("这是一个私有函数!")
end
 
function module.func3()
    func2()
end
 
return module

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

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


require 函数

Lua提供了一个名为require的函数用来加载模块。要加载一个模块,只需要简单地调用就可以了。

  • 运行指定文件
  • 末尾不带拓展名
  • 目录层级用"."分隔
  • 只会运行一次
  • 从package.path中的路径里查找

例如:

require("<模块名>")

或者

require "<模块名>"

执行 require 后会返回一个由模块常量或函数组成的 table,并且还会定义一个包含该 table 的全局变量。

test_module.lua 文件

-- test_module.lua 文件
-- module 模块为上文提到到 module.lua
require("module")
 
print(module.constant)
 
module.func3()

以上代码执行结果为:

这是一个常量
这是一个私有函数!

或者给加载的模块定义一个别名变量,方便调用:

test_module2.lua 文件

-- test_module2.lua 文件
-- module 模块为上文提到到 module.lua
-- 别名变量 m
local m = require("module")
 
print(m.constant)
 
m.func3()

以上代码执行结果为:

这是一个常量
这是一个私有函数!

加载机制

对于自定义的模块,模块文件不是放在哪个文件目录都行,函数 require 有它自己的文件路径加载策略,它会尝试从 Lua 文件或 C 程序库中加载模块。

require 用于搜索 Lua 文件的路径是存放在全局变量 package.path 中,当 Lua 启动后,会以环境变量 LUA_PATH 的值来初始这个环境变量。如果没有找到该环境变量,则使用一个编译时定义的默认路径来初始化。

当然,如果没有 LUA_PATH 这个环境变量,也可以自定义设置,在当前用户根目录下打开 .profile 文件(没有则创建,打开 .bashrc 文件也可以),例如把 "~/lua/" 路径加入 LUA_PATH 环境变量里:

#LUA_PATH
export LUA_PATH="~/lua/?.lua;;"

文件路径以 ";" 号分隔,最后的 2 个 ";;" 表示新加的路径后面加上原来的默认路径。

接着,更新环境变量参数,使之立即生效。

source ~/.profile

这时假设 package.path 的值是:

-- 打印 package.path的 值

print(package.path)

/Users/dengjoe/lua/?.lua;./?.lua;/usr/local/share/lua/5.1/?.lua;/usr/local/share/lua/5.1/?/init.lua;/usr/local/lib/lua/5.1/?.lua;/usr/local/lib/lua/5.1/?/init.lua

那么调用 require("module") 时就会尝试打开以下文件目录去搜索目标。

/Users/dengjoe/lua/module.lua;
./module.lua
/usr/local/share/lua/5.1/module.lua
/usr/local/share/lua/5.1/module/init.lua
/usr/local/lib/lua/5.1/module.lua
/usr/local/lib/lua/5.1/module/init.lua

如果找过目标文件,则会调用 package.loadfile 来加载模块。否则,就会去找 C 程序库。

搜索的文件路径是从全局变量 package.cpath 获取,而这个变量则是通过环境变量 LUA_CPATH 来初始。

搜索的策略跟上面的一样,只不过现在换成搜索的是 so 或 dll 类型的文件。如果找得到,那么 require 就会通过 package.loadlib 来加载它。


案例实战

案例:lua 上运行 redis

第一步: Window 系统上安装 Lua(如果已安装则可忽略)

  • Github 下载地址:https://github.com/rjpcomputing/luaforwindows/releases

 安装好之后,需要将 ‪D:\software\lua\5.1\lua.exe 添加到环境变量中

第二步:Window 系统上安装 luaRocks

luaRocks 是什么?

LuaRocks 是一个用于管理 Lua 模块的包管理器。它允许用户轻松地安装、更新和管理 Lua 库和模块。通过 LuaRocks,用户可以从在线的 Lua 库仓库中下载和安装所需的模块,也可以创建自己的模块包并分享给其他用户。

下载 luaRocks

下载luaRocks,它是一个lua相关类型的维护工具包,下载地址:luarocks 下载。

安装 luaRocks

下载后从cmd命令行中运行Install.bat安装。

点击 Install.bat 之后会卡在红色框框那,直接按 Enter 键 安装完成。

第三步:从cmd 命令中安装 redis-lua 模块

luarocks install redis-lua

第四步:在lua.exe中执行以下命令.

redis = require 'redis'
-- 创建一个Redis连接对象
client = redis.connect('127.0.0.1', 6379)
-- 设置键值对
client:set('foo', 'bar')
-- 获取并打印键的值
print(client:get('foo')) 
-- 关闭连接
client:close()

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2230528.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Java:数据结构-MapSet

搜索树 二叉搜索树又称二叉排序树&#xff0c;它或者是一棵空树&#xff0c;或者是具有以下性质的二叉树 若它的左子树不为空&#xff0c;则左子树上所有节点的值都小于根节点的值若它的右子树不为空&#xff0c;则右子树上所有节点的值都大于根节点的值它的左右子树也分别为…

全新更新!Fastreport.NET 2025.1版本发布,提升报告开发体验

在.NET 2025.1版本中&#xff0c;我们带来了巨大的期待功能&#xff0c;进一步简化了报告模板的开发过程。新功能包括通过添加链接报告页面、异步报告准备、HTML段落旋转、代码文本编辑器中的文本搜索、WebReport图像导出等&#xff0c;大幅提升用户体验。 FastReport .NET 是…

楼梯区域分割系统:Web效果惊艳

楼梯区域分割系统源码&#xff06;数据集分享 [yolov8-seg-FocalModulation&#xff06;yolov8-seg-GFPN等50全套改进创新点发刊_一键训练教程_Web前端展示] 1.研究背景与意义 项目参考ILSVRC ImageNet Large Scale Visual Recognition Challenge 项目来源AAAI Global Al l…

CentOS 文件系统扩容与缩容

一、 概述 理解Linux文件系统的管理&#xff0c;需要了解以下的一张图&#xff1a; 一般使用LVM (Logical Volume Manager) 管理磁盘存储&#xff0c;该工具允许用户更灵活地分配和管理存储空间。主要有以下几个概念&#xff1a; PV&#xff08;Physical Volume&#xff0c;物…

电能质量治理产品在分布式光伏电站的应用

1.概述 随着全球对可再生能源需求的不断增长&#xff0c;分布式光伏电站的建设与扩张正迅速发展。然而&#xff0c;在其运行过程中&#xff0c;分布式光伏电站遭遇了一系列挑战&#xff0c;包括企业关口计量点功率因数降低和谐波污染等问题。这些问题不仅影响了光伏电站的运行…

ssm038汽车养护管理系统+jsp(论文+源码)_kaic

毕 业 设 计&#xff08;论 文&#xff09; 题目&#xff1a;汽车养护管理系统设计与实现 摘 要 现代经济快节奏发展以及不断完善升级的信息化技术&#xff0c;让传统数据信息的管理升级为软件存储&#xff0c;归纳&#xff0c;集中处理数据信息的管理方式。本汽车养护管理系统…

Linux系统每日定时备份mysql数据

一、创建存储脚本的文件夹 创建文件夹&#xff0c;我的脚本放在/root/dbback/mysql mkdir ... cd /root/dbback/mysql 二、编写脚本 vi backup_mysql.sh 复制脚本内容 DB_USER"填写用户名" DB_PASSWORD"填写密码" DB_NAME"数据库名称" # …

Spring Boot 注解大全:全面解析 Spring Boot 常用注解及其应用场景

Spring Boot 注解大全:全面解析 Spring Boot 常用注解及其应用场景 简介 Spring Boot 是一个基于 Spring 框架的简化开发框架,它旨在简化 Spring 应用的初始搭建和开发过程。Spring Boot 提供了一系列的注解,使得开发者可以更加方便地进行应用开发和配置。本文将详细介绍 S…

用Python将PDF表格提取到文本、CSV和Excel文件中

从PDF文档中提取表格并将其转换为更易于处理的格式&#xff08;如文本、CSV和Excel文件&#xff09;&#xff0c;是数据分析和信息管理中的常见需求。此过程可显著简化表格数据的处理&#xff0c;使数据的操作、分析和与其他数据集的集成更加便捷。无论是财务报表、研究论文&am…

Linux下cgdb/gdb调试以及关于操作系统那些事

目录 一.gdb调试 1.1debug和release版本有什么区别? 1.2性能优化 1.3gdb的使用 1.4cgdb的安装 二.什么是硬件 三.冯诺依曼体系 四.操作系统(OS) 4.1理解操作系统 4.1.1操作系统是什么? 4.1.2为什么要有操作系统? 4.1.3 OS-银行 4.1.4OS如何管理 理解库文件和系…

GPU-主板-内存-硬盘-CPU-电源分类及区别总结大全

一、背景 用了7年的笔记本&#xff0c;现在感觉它实在是扛不住了&#xff0c;中间自己缝缝补补坚持到现在&#xff0c;把机械硬盘换成了固态&#xff0c;加装了内存条。换过2次还是3次风扇&#xff08;不知道为啥坏的&#xff0c;高转速时哧哧响&#xff09;&#xff0c;换过一…

10款舞台剧免费音频剪辑软件分享,你用过哪款?

在舞台剧的世界里&#xff0c;音乐是情感的传递者&#xff0c;是气氛的营造者。一个好的舞台剧&#xff0c;离不开精心剪辑的背景音乐。而选择合适的音频剪辑软件&#xff0c;就如同挑选舞台上的演员一样重要。今天&#xff0c;我们就从舞台剧音乐剪辑的角度&#xff0c;来聊聊…

C#/.NET/.NET Core技术前沿周刊 | 第 11 期(2024年10.21-10.31)

前言 C#/.NET/.NET Core技术前沿周刊&#xff0c;你的每周技术指南针&#xff01;记录、追踪C#/.NET/.NET Core领域、生态的每周最新、最实用、最有价值的技术文章、社区动态、优质项目和学习资源等。让你时刻站在技术前沿&#xff0c;助力技术成长与视野拓宽。 欢迎投稿、推荐…

w~Transformer~合集8

我自己的原文哦~ https://blog.51cto.com/whaosoft/12419881 #Batch Normalization 本文聚焦于Batch Normalization&#xff0c;Layer Normalization两个标准化方法&#xff0c;对其原理和优势等进行了详细的阐述。 这一篇写Transformer里标准化的方法。在Transformer中&am…

【天线&空中农业】花生霉变检测系统源码&数据集全套:改进yolo11-LVMB

改进yolo11-goldyolo等200全套创新点大全&#xff1a;花生霉变检测系统源码&#xff06;数据集全套 1.图片效果展示 项目来源 人工智能促进会 2024.11.01 注意&#xff1a;由于项目一直在更新迭代&#xff0c;上面“1.图片效果展示”和“2.视频效果展示”展示的系统图片或者视…

鸿蒙开发融云demo发送图片消息

鸿蒙开发融云demo发送图片消息 融云鸿蒙版是不带UI的&#xff0c;得自己一步步搭建。 这次讲如何发送图片消息&#xff0c;选择图片&#xff0c;显示图片消息。 还是有点难度的&#xff0c;好好看&#xff0c;好好学。 一、思路&#xff1a; 选择图片用&#xff1a;photoVie…

天空卫士澳门交流会:AI赋能数据安全,共话未来挑战

10月31日&#xff0c;天空卫士于澳门举办以“Is Your Data Security Strategy Built for the Future?&#xff08;您的数据安全策略能否应对未来挑战&#xff1f;&#xff09;”为主题的澳门用户午餐交流会议。本次活动聚集了来自澳门金融管理局、财政局以及澳门四大酒店集团的…

ELK + Filebeat + Spring Boot:日志分析入门与实践(二)

目录 一、环境 1.1 ELKF环境 1.2 版本 1.3 流程 二、Filebeat安装 2.1 安装 2.2 新增配置采集日志 三、logstash 配置 3.1 配置输出日志到es 3.2 Grok 日志格式解析 3.2 启动 logstash ​3.3 启动项目查看索引 一、环境 1.1 ELKF环境 springboot项目&#xff1a;w…

记录新建wordpress站的实践踩坑:wordpress 上传源码新建站因权限问题导致无法访问、配置新站建站向导以及插件主题上传配置的解决办法

官方文档&#xff1a;How to install WordPress – Advanced Administration Handbook | Developer.WordPress.org 但是没写权限问题&#xff0c;可以下载到 wordpress官方包。 把下载的wordpresscn的包解压并上传到服务器目录下&#xff0c;但是因为是root上传导致了权限问题…

springcloud通过MDC实现分布式链路追踪

在DDD领域驱动设计中&#xff0c;我们使用SpringCloud来去实现&#xff0c;但排查错误的时候&#xff0c;通常会想到Skywalking&#xff0c;但是引入一个新的服务&#xff0c;增加了系统消耗和管理学习成本&#xff0c;对于大型项目比较适合&#xff0c;但是小的项目显得太过臃…