lua 入门

news2025/1/17 4:00:24

安装

linux 下安装方式

curl -R -O http://www.lua.org/ftp/lua-5.4.4.tar.gz
tar zxf lua-5.4.4.tar.gz
cd lua-5.4.4
# 编译并测试没有问题
make all test
make install

卸载

cd lua-5.4.4
# 删除相关配置,之后可以删除 lua-5.4.4
make uninstall

执行

文件以 .lua 结尾

方式一

# 先查找 lua 解释器的路径
which -a lua

在这里插入图片描述
hello.lua 文件添加解释器路径

#!/usr/local/bin/lua
print("Hello Lua!")

添加可执行权限

chmod u+x ./hello.lua

运行

./hello.lua

方式二

lua hello.lua

注释

-- 单行注释

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

--[[
多行注释
]]

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

-- 取消多行注释,取消后注释中的代码可以执行
---[[
print("Hello Lua!")
--]]

交互

# 进入交互模式,或者 lua -i
lua
# 交互模式下退出,或者 ctrl+c 强制中断,或者 ctrl+D 发送退出信号
os.exit()

请添加图片描述
请添加图片描述

标识符

以字母、数字、下划线组成,数字不能开头

区分大小写

关键字

ifelseelseifnil
returnwhilebreakend
endnotthengoto
dofalsetruein
orfunctionforlocal
repeatuntil

变量

全局变量

一般约定,以下划线开头连接一串大写字母的名字(如: _VERSION)被保留(或用于) lua 内部全局变量

默认情况下,变量总是全局的

-- 全局变量不需要声明,访问一个没有初始化的全局变量不会出错,结果默认为 nil
print(b) -- nil
b=10
print(b) -- 10
-- 删除全局变量
b=nil
print(b) -- nil

请添加图片描述

_G

保存全局环境的全局变量,改变它的值不会影响任何环境,只会影响自己的代码

--[[
	_G 不能使用 local 修饰
	local _ENV 可以指定局部环境变量 
--]]
function fn()
    -- 当前环境中只有 print 可用
    local _ENV = {print=_G.print}
    print(os)
    print(print)
end
fn()
-- 不影响
print(os)

局部变量

局部变量的作用域为从声明位置开始到所在语句块结束

局部变量的访问速度比全局变量更快

do
	local a=5 -- 使用 local 修饰
	print(a)
end
print(a)

在这里插入图片描述

赋值

lua 可以对多个变量同时赋值

a,b=1,2
print(a,b) -- 1 2
a,b=b,a
print(a,b) -- 2 1

数据类型

类型描述
nil小写的(L),表示无效值
booleantrue、false
number双精度的实浮点数
string双引号和单引号包含的内容,如: “lua”
function函数
userdata用户自定义数据,将 C/C++ 的任意数据类型的数据(通常是 struct 和指针)存储到 lua 变量中
thread线程,用于执行 coroutine (协程)
table“关联数组”,索引可以是数字、字符串、表类型

type

是一个函数,测定变量或值的类型

返回的是类型的字符串

print(type(a)) -- nil
print(type("lua")) -- string
print(type(1))	-- number
print(type(print)) -- function
print(type(true)) -- boolean
print(type(type(1))) -- string
print(type({})) -- table

string

一对单引号或双引号表示

a="lua"
b='lua'

使用 [[]][=[]=] 来表示多个行构成的字符串

s=[[
<html>
<head></head>
<body></body>
</html>
]]

字符串和数字进行算数操作, lua 会尝试将字符串转为数字进行运算
在这里插入图片描述

使用 .. 进行字符串的拼接
在这里插入图片描述
使用 # 获取字符串长度,不能准确获取多字节构成的字符串的长度
在这里插入图片描述

table

table 通过"构造表达式"创建,一个简单的方式是使用 {} 来创建

local t1={} -- 空 table
local t2={1,2,"abc"} -- 可以存储多个类型
print(t2[1]) -- 默认下标从 1 开始

在这里插入图片描述

table 索引可以是字符串,可以看做 python 中的字典

a={}
a["name"]="tom"
a["age"]=18
for k,v in pairs(a) do
    print(k .. ":" .. v)
end

t={name="tom",age=18, "earth"}
-- 当索引是字符串时 [] 可以简化成 .
-- 当 table 的索引既有字符串,又有数字时,t[1]为第一个索引为数字的元素
print(t.name,t["name"], t[1]) -- tom tom earth
t=nil -- 删除

table 长度不固定,数据添加时会自动增长,可以考虑 java 中的 Map

function

函数可以作为变量

function cal(a, b, fn)
    return fn(a,b)
end
a=1
b=2
-- 可以使用匿名方式传参
print(cal(a,b, function(a,b) return a + b end))

utf8 支持

s = "abc他们"
-- 获取字符个数
print(utf8.len(s))
-- i 是字符在字节中开始的位置,v 是字符的码点
for i,v in utf8.codes(s) do
    print(i, v)
end
-- 获取 s 的全部码点
print(utf8.codepoint(s,1,-1))
-- 将码点转为字符串
print(utf8.char(97,98))
-- 返回第 4 个字符在字节中的开始处
print(utf8.offset(s,4))

在这里插入图片描述

运算符

算术运算符

a,b=4,2
-- 加法
print("a + b = "..a + b)
-- 减法
print("a - b = "..a - b)
-- 乘法
print("a * b = "..a * b)
-- 除法
print("a / b = "..a / b)
-- 取余
print("a % b = "..a % b)
-- 幂
print("a ^ b = "..a^b)
-- 负
print("-a = "..-a)
-- 整除
print("a // b = "..a//b)

在这里插入图片描述

关系运算符

操作符说明
==等于,相等为 true, 不等为 false
~=不等于,不相等为 true, 相等为 false
>大于
<小于
>=大于等于
<=小于等于

逻辑运算符

nilfalse 为假,其他为真,注意 0 也为真

not 将真变为假,将假变为真

右值为 boolean 时的运算

a,b = true,false
-- 逻辑与
print(a and b)
-- 逻辑或
print(a or b)
-- 逻辑非
print(not a)

在这里插入图片描述
右值不全是 boolean 时的运算

a,b,c = 1,2,nil
print(a and b) -- a 为真,则返回 b,否则返回 a
print(c and a)
print(string.rep("-", 5))
print(a or b) -- a 为真,则返回 a,否则返回 b
print(c or a)
print(string.rep("-", 5))
print(not a) -- 真变为假
print(not c) -- 假变为真

在这里插入图片描述

按位运算符

a,b=8,2
print(a & b) -- 与
print(a | b) -- 或
print(a ~ b) -- 异或
print(~a)    -- 非
print(a >> b) -- 右移
print(a << b) -- 左移

在这里插入图片描述

其他运算符

-- .. 连接两个字符串
print("Hello ".."Lua")
-- # 一元运算符,返回字符串或表的长度
t={1,2,3}
print(#t)

在这里插入图片描述

运算符优先级

^.. ,其他的二元运算符都是左连接的

操作符优先级(1最高)
^1
not - (负号)2
* / % //3
+ -(减号)4
5
< > <= >= ~= ==6
and7
or8

语句块

-- do...end 作为语句块
do
    local i = 5
    print(i)
end
print(i)

在这里插入图片描述

流程控制

if 语句

-- false 和 nil 为假
-- true 和 非nil 为真
-- 0 为 true
flag = true
if (flag) then
    print("true")
end

if-else 语句

flag = false
if (flag) then
    print("true")
else
    print("false")
end    

if-elseif 语句

score = 85
if (score <= 60) then
    print("不及格")
elseif (score <= 80) then
    print("良好")
elseif (score <= 90) then
    print("中等")
else
    print("优秀")
end    

if 嵌套

target = 92
if (target <= 100) then
    if (target >= 90) then
        print("在90-100范围")
    else
        print("小于90")
    end
else
    print("超出范围")
end

循环

循环可以嵌套使用

while 循环

local i = 0
while (i < 9) do
-- 输出
io.write(i,",")
i = i + 1
end
io.write(i, "\n")

在这里插入图片描述

无限循环

while (true) do
    print("一条信息")
end

for 循环

--[[
-- var 从 exp1 以 exp3 为步长增长到 exp2
-- 闭区间 [exp1,exp2]
-- exp3 可选,默认为1
-- exp1,exp2,exp3 在循环开始前一次性求值,以后不再进行求值
for var=exp1,exp2,exp3 do
	statement
end
--]]
for i=1,10,2 do
    -- 对于 i 的值的修改不影响循环次数
    print(i)
end

-- 使用 for 来输出 table
a = {"a", "b", "c", name="tom"}
-- ipairs 只对数字索引生效,遇到 nil 将会退出
for k,v in ipairs(a) do
    print(k..":"..v)
end

在这里插入图片描述

repeat…until 循环

与 C 语言的 do-while 类似

i = 5
repeat
    print(i)
    i = i - 1
until(i < 1)   

在这里插入图片描述

循环控制

break 跳出循环

i = 1
while (i < 10) do
	print(i)
    if (i > 4) then
    	print("跳出循环")
        break
    end
    i = i + 1
end

在这里插入图片描述

goto 跳转到指定标签处

--[[
goto label
-- label 格式
::Label::
--]]
i = 1
::A::
if (i < 5) then
    print(i)
    i = i + 1
    goto A
end
print("end")

在这里插入图片描述

数组

一维数组

arr = {4,5,2}
for i=1,#arr do
	print(arr[i])
end

多维数组

arr = {}
for i=1,2 do
	arr[i] = {}
    for j = 1, 2 do
       	arr[i][j] = j 
    end
end

for i=1,2 do
	for j=1,2 do
    	print(arr[i][j])
    end
end

函数

定义

scope function function_name(arg1,arg2,...)
	statement
	return statement
end

scope: 可选,指明函数是全局函数还是局部函数,默认为全局函数,局部函数取值为 local

function_name: 函数名

arg1,arg2: 参数,可以0个或多个

return statement: 可以返回多个值,用逗号 , 隔开

local function max(a,b)
	if (a > b) then
        return a
    else
        return b
    end
end
a,b=10,20
print(max(a,b))

函数作为右值

add = function(a, b)
    return a + b
end
print(add(1,2))

函数作为参数

function cal(a,b,fn)
	return a,fn(a,b)
end
a,b=cal(10,20,function(a,b) return a + b end)
print(a, b)

在这里插入图片描述

函数作为返回值

function linear(k)
	return function(x,b)
    	return k * x + b 
    end
end
fn = linear(2)
print(fn(1,1))
print(fn(2,2))

在这里插入图片描述

可变参数

使用 ... 表示可变参数,固定参数必须放在可变参数之前

function fn(...)
    -- {...} 选取可变参数中非 nil 的参数构成的数组
	for k,v in pairs({...}) do
    	io.write(v.." ")
    end
    print()
end
fn(1,2,nil,4,nil,nil)

在这里插入图片描述

使用 # 获取可变参数的长度,存在 nil 时不准确

function fn(...) 
	print("可变参数个数: "..#{...})
end
fn(1,2,3,nil,5,nil)

在这里插入图片描述

使用 select 获取可变参数的长度

function fn(...)
    -- 可以处理出现 nil 的情况
	print("可变参数个数: "..select("#", ...))
    --[[
    	select(n,...) 返回从 n 开始到最后的所有的参数列表
    	n 从 1 开始,也可以取负值,-1表示最后一个参数
    --]]
    a,b,c,d = select(1,...)
    print(a,b,c,d)
    print(select(1,...))
end
fn(1,2,3,nil,5,nil)

在这里插入图片描述

next

--[[
	-- index 为索引默认为 nil
	-- 函数返回表的下一个索引和值,将 index 取值为该索引可以获取下一个索引和值
	-- 返回的索引和值的顺序不固定
	-- index 为 nil 时,返回一个初始索引和值
	-- 可以判断表是否为空
	next(table[,index])
--]]
t = {name="tom",age=18,20}
k,v=next(t)
while(true) do
	if (k) then
        print(k,v,t[k])
        k,v=next(t,k)
    else
        break
    end
end

在这里插入图片描述

assert

--[[
	-- v 为 false 或 nil 时断言失败
	-- message 是字符串,断言失败的信息
	-- 断言成功返回所有参数
	assert(v[,message])
--]]
print(assert(1,"断言成功"))

在这里插入图片描述

tonumber

--[[
	-- base 取值 [2,36],指定 e 的进制,默认 10
	tonumber(e[,base])
--]]
print(tonumber("16"))
print(tonumber("16",16))

在这里插入图片描述

tostring

--[[
	-- 将任意类型 v,转为字符串
	tostring(v)
--]]
print(tostring(1), type(tostring(1)))
print(tostring(nil), type(tostring(nil)))
print(tostring({name=tom,10}), type(tostring({name=tom,10})))

在这里插入图片描述

pcall

--[[
	-- 在保护模式下使用给定参数调用函数 f,函数 f 中的错误不会传播
	-- pcall 捕获错误并返回状态代码
	-- 返回的第一个值是状态码 true 或 false
	-- 状态码是 true,还会返回所有调用结果
	-- 状态码是 false,还会返回 error 对象
	pcall(f[,arg1,...])
--]]
f,t = pcall(assert, false, "断言失败")
print(f,t)

在这里插入图片描述

xpcall

提供一个错误处理函数,可以获取更多的调试信息

f, t = xpcall(assert, function (err)
    print(err)
    return debug.traceback()
end, 1 == 2 , "断言失败")
print(f,t)

在这里插入图片描述

dofile

打开命名文件并将其内容作为 Lua 块执行。当不带参数调用时,dofile 执行标准输入 stdin 的内容。返回该块返回的所有值。如果出现错误,dofile 将错误传播给它的调用者。也就是说,dofile 不会在保护模式下运行。

--[[
	dofile([filename])
--]]

load

--[[
	-- chunk 最终是一个字符串
	-- 没有语法错误,load 返回一个函数,否则返回 nil 和 错误信息
	-- chunkname 用作错误消息和调试信息的块的名称
	-- mode:"b",只是二进制块;"t",只是文本块;"bt",文本和二进制块。默认为 "bt"
	-- env 是 _ENV 传入一个 table
	-- 运行恶意制作的字节码会使解释器崩溃
	load(chunk[,chunkname[,mode[,env]]])
--]]
local f,msg = load([[print("tom")]], "运行错误","bt",{print=_G.print})
pcall(f)

在这里插入图片描述

loadfile

类似于 load,但如果没有给出文件名,则从标准输入获取块。

--[[
	loadfile([filename[,mode[,env]]])
--]]

table

concat

--[[
-- 将表 list 从 list[i] 到 list[j] 以字符串 sep 连接 
table.concat(list,sep,i,j)
--]]
t = {"a", "b", "c"}
print(table.concat(t, "-", 1, 3))

在这里插入图片描述

insert

--[[
	-- 在指定的 list[pos] 位置插入 value 
	table.insert(list, pos, value) 
--]]
t = {"a", "b", "c"}
table.insert(t, 1, "d")
for k, v in pairs(t) do
    print(v)
end

在这里插入图片描述

remove

--[[
    -- 删除 list[pos] 位置元素
    table.remove(list, pos)
--]]
t = {"a", "b", "c", "d"}
-- 默认删除最后一个
table.remove(t)
for k, v in pairs(t) do
    print(v)
end
print(string.rep("=", 5))
table.remove(t, 2)
for k, v in pairs(t) do
    print(v)
end

在这里插入图片描述

sort

--[[
    -- 按照 comp 函数进行排序
    table.sort(list, comp)
--]]
a = {3, 10, 8, 2, 4}
table.sort(a, function (a,b)
    return a > b
end)
for k,v in pairs(a) do
    print(v)
end

在这里插入图片描述

pack

构建 table

function fn(...) 
    -- pack 将非 nil 的值构建成 table,并添加一个 k=v,其中 k 是 n,v 是值的全部个数
    t = table.pack(...)
    for k,v in pairs(t) do
    	print(k..":"..v)
    end
end
fn(1,2,3,nil,5,nil,nil)

在这里插入图片描述

unpack

--[[
	-- 返回表 list[i] 到 list[j] 中的元素
	table.unpack(list,i,j)
--]]
list = {1,2,3,nil,5,nil,nil,6,nil}
-- 从 list[1] 到 list[j] 的元素,list[j]是从右向左第一个不为 nil 的元素
print(table.unpack(list))
-- list[2] 到 list[7] 的元素
print(table.unpack(list,2,7))

在这里插入图片描述

获取表长

-- 使用该种方式构建 table 时, 用 # 方式获取表长,当最后的元素为 nil 时,会导致长度不准确 
list = {nil,1,2,3,nil,5,nil,nil,6,nil}
-- # 获取的长度是 list[1] 到 list[j] 的个数,list[j]为从右向左第一个不为 nil 的元素
print(#list)

在这里插入图片描述
使用 pack 方式构建可以解决上述问题

-- pack 构建 table 时,添加了键 n,该键的值是 table 的表长
list = table.pack(nil,1,2,3,nil,5,nil,nil,6,nil)
-- 表长
print(list.n) -- list["n"]
for i=1,list.n - 1 do
	io.write(list[i] or "nil","\t")
end
io.write(list[list.n] or "nil")
print("")

在这里插入图片描述

table 中 function 的使用

function sub(a,b)
	return a - b
end
t = {add=function(a,b) return a + b;end,sub=sub}
-- print(t["add"](1,2))
print(t.add(1,2))
print(t.sub(1,2))

迭代器

ipairs

第一次遇到 nil 将停止迭代

t = {1,2,3,nil,4,5}
for k,v in ipairs(t) do
    print(k..":"..v)
end

在这里插入图片描述

pairs

遇到 nil 不会停止迭代

t = {1,2,3,nil,4,5}
for k,v in pairs(t) do
    print(k..":"..v)
end

在这里插入图片描述

元表与元方法

元表(metatable),可以改变 table 的行为,每个行为关联了对应的方法(元方法)

元方法说明
__add运算符 +
__sub运算符 -
__mul运算符 *
__div运算符 /
__idiv运算符 //
__mod运算符 %
__unm运算符负号 -
__concat运算符 …
__eq运算符 ==
__lt运算符 <
__le运算符 <=
__band按位与运算,如: 1 & 2
__bor按位或运算,如: 1 | 2
__bxor按位异或运算,如: 1 ~ 2
__bnot按位非运算,如: ~ 1
__shl按位左移运算,如: 1 << 2
__shr按位右移运算,如: 8 >> 2
__len# 操作
__index访问表
__newindex对表进行更新
__call让表像函数一样调用
__tostring修改表的输出行为

setmetatable

对指定的 table 设置元表,若元表中存在 __metatable 键值,setmetatable 会失败

--[[
	setmetatable(table,metatable)
--]]
list = {1,2,3,nil,5,nil,nil,6,nil}
t = {}
-- 返回 list
t1 = setmetatable(list, t)
print(table.unpack(t1))

getmetatable

返回指定 table 的元表

list = {1,2,3,nil,5,nil,nil,6,nil}
t = {10,nil,nil,11}
setmetatable(list, t)
m = getmetatable(list)
print(table.unpack(m))

在这里插入图片描述

rawset 和 rawget

t = {name="tom"}
t1 = {score=99}
setmetatable(t,t1)
print(rawget(t, "name")) -- 不对元表操作,只获取表 t 中的索引值,不存在返回 nil
print(rawget(t, "score"))
rawset(t, "address", "earth") -- 不调用元表中的方法,只更新表 t
print(t.address)
print(t1.address) -- 元表中不存在

在这里插入图片描述

rawequal

--[[
	-- 语法,判断 v1 和 v2 是否相等,不调用 __eq 元方法,返回 true 或 false
	-- v1,v2 任意类型
	rawequal(v1,v2)
--]]
print(rawequal(1,1))
print(rawequal(1,2))
print(rawequal(1,nil))
print(rawequal(1,"1"))

在这里插入图片描述

rawlen

--[[
	-- 语法,v 只能是字符串和 table,返回 v 的长度,不调用任何元方法
	rawlen(v)
--]]
print(rawlen("hello"))
print(rawlen({1,2,nil,3}))

在这里插入图片描述

__index

通过索引访问 table 时,若该索引没有值,则寻找该 table 对应的 metatable 中的 __index中的索引

t = {name="tom"}
setmetatable(t,{__index=function(t,k) if k == "age" then return 18; end end})
print(t.name)
-- 访问元表
print(t.age)

在这里插入图片描述

将函数简化成 table, 形式更为简洁

t = {name="tom"}
setmetatable(t,{__index={age=18, address="earth"}})
print(t.name)
print(t.age) -- 访问元表
print(t.address)
print(t.score) -- 元表中也不存在

在这里插入图片描述

__newindex

给指定表的不存在的索引赋值时,会查找 __newindex 元方法,并将键值存在 __newindex 值中

t = {name="tom"}
t1 = {}
setmetatable(t,{__newindex=t1})
t.address="earth" 
print(t.address) -- 表中不存在
print(t1.address)
print(string.rep('-',5))
t.score=89 
print(t.score) 
print(t1.score)
print(string.rep("-",5))
for k,v in pairs(t) do
    io.write(k..":"..v," ")
end
print("")
for k,v in pairs(t1) do
    io.write(k..":"..v," ")
end
print("")

在这里插入图片描述
利用 __newindex 为指定表更新值

t = {name="tom"}
t1 = {}
setmetatable(t,{
    __newindex=function(t, index, value)
        -- rawset 不会调用 `__newindex` 元方法,并为表 t 设置值
        -- 不使用该方法,直接 t[index] = value 会调用 __newindex,导致死循环    
        rawset(t, index, value)
    end
})
t.name="jerry" -- t 中有 name, 直接更新 t,不调用元方法
print(t.name) 
print(string.rep("-",5))
t.age=18 -- t 中没有 age,查找 __newindex 元方法
print(t.age) 
print(t1.age)
print(string.rep("-",5))
t.score=89 
print(t.score) 
print(t1.score)
print(string.rep("-",5))
for k,v in pairs(t) do
    io.write(k..":"..v," ")
end
print("")
-- 修改了 __newindex,所以 t1 中不存在值 
for k,v in pairs(t1) do
    io.write(k..":"..v," ")
end
print("")

在这里插入图片描述

__tostring

修改 table 的输出行为

t = {1,2,3,nil,10}
setmetatable(t,{
    __tostring=function(t)
        s = t[1] or "nil"
        for i=2,#t do
            s = s..","..(t[i] or "nil")
        end
        return s
    end
})
print(t)

在这里插入图片描述

__call

让表像函数一样调用

t = {1,2,3,nil,10}
setmetatable(t,{
    __call=function(t,t1,t2)
        print(t1,t2)
        s = 0
        for i=1,#t do
            s = s + (t[i] or 0)
        end
        return s
    end
})
-- 对 t 进行求和
print(t(1,2))

在这里插入图片描述

__add

让表具有 + 的功能

t = {1,2,3,nil,10}
t1 = {11,nil,9,8}
setmetatable(t,{
    __add=function(t,t1)
        t2 = {}
        for i=1,#t do
            t2[i] = t[i]
        end
        len = #t
        for i=1,#t1 do
            t2[len + i] = t1[i]
        end
        return t2
    end
})
-- 将 t 和 t1 中的元素合并,并返回一个新的表
t2 = t + t1
print(table.unpack(t2))

在这里插入图片描述

__unm

t = {1,2,3}
t1 = {
    __unm = function(t)
        for i=1,#t do
            if (type(t[i]) == "number") then
                t[i] = -t[i]
            end
        end
        return t
    end
}
setmetatable(t,t1)

print(table.unpack(-t))

在这里插入图片描述

面向对象

.: 定义函数

.: 定义函数的区别在于 : 会提供一个隐含的 self 参数,该参数是当前的 table

Person = {name="tom", age=18}
--[[
	-- 与下面的等价
	Person.getName = function() 
		return Person.name
	end
--]]
function Person.getName()
    return Person.name
end
--[[
	-- 与下面等价,注意调用时使用的是 Person:getAge()
	-- self 只是参数名,可以替换成其他的参数名,如:s,一般使用 self
	-- : 方式调用,lua 会将当前表作为参数传递给第一个参数
	Person.getAge = function(self)
		return self.age
	end
	-- 该种方式传参,调用方式 Person:setScore(98)
	-- . 方式调用,需要手动传入,Person.setScore(Person,99)
	Person.setScore = function(self,score) 
		self.score = score
		print(self.score)
	end
--]]
-- 这种方式定义, lua 会自动传入一个参数名为 self 的参数,指代 table,注意其他参数名不要与之相同
function Person:getAge()
    print(self,Person)
    return self.age
end
-- 怎么定义的怎么调用,推荐使用上面非注释的方式定义
print(Person.getName())
print(Person:getAge())

在这里插入图片描述

创建对象

Person = {name="name",age=0}
function Person:new() 
	o = {}
    -- 设置自索引,当 o 访问的索引不存在时,将会查找元表
    self.__index = self
    -- 为 o 设置元表,放在所有元方法之后
    setmetatable(o, self)
    return o
end
p = Person:new()
p1 = Person:new()
p.name = "tom"
p.age = 18
print(p.name,p.age)
print(p1.name, p1.age)

在这里插入图片描述

继承和重写

Person = {
    name="name",
    age=0
}

Person.__index = Person

function Person:work()
    print("工作")
end

Student = {}
setmetatable(Student, Person)
-- 继承
print(Student.name, Student.age)
Student:work()
print(string.rep("-",5))
-- 重写
function Student:work()
    print("学习")
end
Student:work()

在这里插入图片描述

多重继承

注意添加 __index 即可

成员私有化

function createPerson()
    local name = ""
    local age = 0
    local function getName()
        return name
    end
    local function getAge()
        return age
    end
    local function setName(n_name)
        name = n_name
    end
    local function setAge(n_age) 
        age = n_age
    end
    -- 提供指定的方法获取和修改属性
    return {
        getName=getName,
        getAge = getAge,
        setName=setName,
        setAge=setAge
    }
end

p = createPerson()
p.setName("tom")
p.setAge(18)
print(p.getName(),p.getAge())

coroutine

拥有独立的堆栈,独立的局部变量,独立的指令指针,同时又与其它协程共享全局变量和其它大部分东西。

在任一指定时刻只有一个协程在运行,并且这个正在运行的协程只有在明确的被要求挂起的时候才会被挂起。

语法

coroutine.close(co)关闭协程 co,即关闭其所有待关闭的变量,并将协程置于 "dead" 状态。给定的协程必须已死或挂起。如果出现错误,则返回 false 和错误对象;否则返回 true
coroutine.create(f)创建一个新的协程,f 必须是一个函数。返回一个新的协程,一个类型为 "thread" 的对象。
coroutine.isyieldable([co])当协程 co 可以挂起时返回 true。co 的默认值是正在运行的协程。
coroutine.resume(co [, val1, ···])开始或继续协程的执行。当第一次恢复一个协程时,它开始运行它的主体。值 val1,... 作为参数传递给函数。如果协程已经挂起,将重新启动它;值 val1,... 将作为 yield 的返回结果。如果协程运行时没有任何错误,resume 返回 trueyield 的参数值或函数返回的任何值(当协程终止时)。如果有任何错误,resume 返回 false 和错误消息。
coroutine.running()返回正在运行的协程和一个布尔值,当运行的协程是主协程时为 true
coroutine.status(co)返回协程的状态: "running""suspended""dead""normal"
coroutine.wrap(f)创建一个新的协程,f 必须是一个函数。返回一个函数,该函数在每次调用协程时恢复协程。传递给该函数的任何参数都充当要继续的额外参数。该函数返回与 resume 返回的值相同的值,除了第一个布尔值。如果发生错误,该函数关闭协程并传播错误。
coroutine.yield(···)暂停调用协程的执行。yield 的任何参数都作为resume 的返回结果。

示例

iresume 返回的是第 iyield 的参数,第 iyield 返回的是第 i+1resume 的参数

function fn(a,b)
    print("fn 调用 yield 前")
    -- 第一次 yield
    local x,y,z = coroutine.yield(a * 10,b * 10,2,3,4)
    print("第一次 yield 返回来自第二次 resume 的参数值:",x,y,z)
    print("fn 调用 yield 后")
    return "fn end"
end

co = coroutine.create(function (a,b)
    -- 第二次 resume 之后,函数 fn 中 没有其他的 yield,故执行 return  
    local r = fn(a,b)
    print("函数 fn 的返回值:",r)
    -- 第二次 yield
    local x,y = coroutine.yield(7,8)
    print("第二次 yield 返回来自第三次 resume 的参数值:",x,y)
    return "结束协程"
end)
-- 第一次 resume 返回的是第一次 yield 的参数值 
print("第一次 resume:",coroutine.resume(co,1,2))
-- 第二次执行 resume 将第一次执行 yield 的挂起转为运行,并将 resume 参数作为第一次 yield 的返回值
-- 同时 resume 将第二次 yield 的参数作为返回值
print("第二次 resume:",coroutine.resume(co, 3, 4,5))
-- 第三次 resume 时,已经没有 yield 且函数有返回值,故将函数的返回值作为 resume 的返回值
-- 并且结束协程
print("第三次 resume:",coroutine.resume(co, 5,6))
-- 第四次 resume,协程已经结束,故返回 false 和 错误信息
print("第四次 resume:",coroutine.resume(co, 5,6))

在这里插入图片描述

文件

io 方法

open

打开文件

语法

-- mode 可选
f = io.open(filename[,mode])

mode

模式说明
r只读方式打开文件,该文件必须存在,默认模式
w打开只写文件,若文件存在,则内容为空,文件不存在,则新建
a以附加的方式打开只写文件,文件不存在,则新建,文件存在,则在文件尾部追加内容
r+以可读写方式打开文件,文件必须存在
w+打开可读写文件,若文件存在,则内容为空,文件不存在,则新建
a+以附加的方式打开可读写文件,文件不存在,则新建,文件存在,则在文件尾部追加内容
b二进制方式打开文件
+对文件既可读也可写

close

关闭文件

语法

-- file 不存在,关闭默认的文件
io.close([file])

flush

向文件写入缓冲区的内容

语法

io.flush()

input

当使用文件名调用时,它将打开命名文件(以文本模式),并将其句柄设置为默认输入文件。当使用文件句柄调用时,它只是将该文件句柄设置为默认输入文件。当不带参数调用时,它将返回当前默认输入文件。如果发生错误,此函数将引发错误,而不是返回错误代码。

语法

io.input([file])

output

input 类似,不同的是 output 设置输出文件

语法

io.output([file])

write

将内容写入缓冲区

语法

-- 参数只能是 stirng 和 number
io.write(...)

read

根据指定要读取内容的给定格式读取文件文件。对于每种格式,该函数返回已读字符的字符串或数字,如果不能读取指定格式的数据,则返回失败。读取失败,将不会继续读取。当不带参数调用时,它使用默认格式读取下一行。

语法

io.read(...)

格式

l(小写的 L) 和 L 只能用于文本文件

格式说明
“n”遵循 Lua 的词法约定,读取数字并将其作为浮点数或整数返回。数字可以有前导空格和符号。这种格式总是读取最长的输入序列,这是一个数字的有效前缀;如果该前缀没有形成有效的数字(例如,空字符串,0x3.4e- )或它太长(超过200个字符),它将被丢弃,格式返回失败。
“a”从当前位置开始读取整个文件。在文件结束时,它返回空字符串;这种格式永远不会失败。
“l”读取下一行,跳过行尾,在文件结束时返回失败。这是默认格式。
“L”读取下一行,保留行结束符(如果存在),在文件结束时返回 nail
number读取不超过这个字节数的字符串,在文件结束时返回 nail。如果 number 为 0,则不读取任何内容并返回空字符串,或在文件结束时失败。

示例

f = io.open("./test.txt", "a+")
io.input(f)
while (true) do
    s = io.read()
    if (s) then
        print(s)
    else
        break
    end
end
io.close(f)

在这里插入图片描述

lines

以读模式打开给定的文件名,并返回一个迭代器函数。当迭代器函数无法读取任何值时,它会自动关闭文件。除了迭代器函数,io.lines 返回另外三个值:两个空值作为占位符,加上创建的文件句柄。因此,当在泛型for循环中使用时,如果循环中出现错误或被 break 中断,文件也将关闭。io.lines() 默认遍历输入文件的行,迭代器在循环结束时不会关闭文件。如果打开文件时出现错误,此函数将引发错误,而不是返回错误代码。

语法

-- filename 是文件名, ... 与 io.read(...) 中的一致
io.lines([filename,...])

popen

打开文件,此功能依赖于系统,并非在所有平台上都可用,推荐使用 open

tmpfile

如果成功,返回一个临时文件的句柄。此文件以 w+r+ 打开,并在程序结束时自动删除。

语法

io.tmpfile()

type

检查文件是否是有效的文件句柄。若是一个打开的文件句柄,则返回字符串 "file";若是一个关闭的文件句柄,则返回字符串 "closed file";若不是一个文件句柄,则返回 nil

语法

io.type(file)

示例

-- test.txt 存在
f = io.open("./test.txt")
print(io.type(f),type(io.type(f)))
io.close(f)
print(io.type(f),type(io.type(f)))
-- 不是一个文件句柄
print(io.type("tt"),type(io.type("tt")))

在这里插入图片描述

file 方法

close

关闭文件,当文件句柄被垃圾回收时,文件会自动关闭。

语法

file:close()

flush

将缓冲区的内容写入文件

语法

file:flush()

lines

io.lines(...) 类似。不同的是,在循环结束时,该方法不会关闭文件。

语法

-- ... 与 io.read(...) 中的一致
file:lines(...)

read

io.read(...) 等价

语法

file:read(...)

write

io.write(...) 等价

语法

file:write(...)

seek

whence 处开始,offset 作为偏移读取文件。offsetnumberwhence 是字符串。如果失败,则返回 nil。默认是 whence"cur"offset0

whence说明
“set”文件开始位置
“cur”文件当前位置
“end”文件结束位置

语法

file:seek([whence[,offset]])

setvbuf

设置文件缓冲区的模式,size 是缓冲区大小,以字节为单位。模式依赖于平台。

mode说明
“no”无缓冲区
“full”全缓冲
“line”行缓冲

语法

file:setvbuf(mode[,size])

简单模式

f = io.open("./test.txt", "a+")
io.input(f)
print(io.read())
io.close(f)

完全模式

使用 file 方法代替 io 方法

f = io.open("./test.txt", "a+")
-- 输出第一行内容
print(f:read())
f:close()

模块

定义一个模块

-- net.lua
net = {}
local local_ip = "127.0.0.1"
local local_port = 8080
function net.ip()
    return local_ip
end
function net.setIP(ip)
    local_ip = ip
end
function net.port()
    return local_port
end
function net.setPort(port)
    local_port = port
end
return net

加载模块

-- test.lua 与 net.lua 在同一路径下
net = require("net")
print(net.ip())
net.setPort(8081)
print(net.port())

package.path

加载模块时查找的路径

print(package.path)
--[[
	假定文件以如下方式存在
	|_test.lua
	|_lib
		|_net.lua
	在 test.lua 中加载 net.lua
	net = require("./lib/net")
--]]
-- 第二种方式
package.path=package.path..";./lib/?.lua"
net = require("net")
print(net.ip())
-- 第三种方式:将 net.lua 文件放在 package.path 查找的路径目录下

调用 C 库

-- 可以通过 package.cpath 来修改加载路径
local path = "./net.so"
-- package.loadlib(libname,funcname) 动态加载库
-- funcname 必须遵循 lua_CFunction 规定
local f = assert(package.loadlib(path, "ip"))
-- 调用库
f()

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

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

相关文章

Flume第一章:环境安装

系列文章目录 Flume第一章&#xff1a;环境安装 文章目录系列文章目录前言一、Flume是什么&#xff1f;二、环境安装1.文件下载2.环境安装3.官方案例三、几个案例1.实时监控 Hive 日志&#xff0c;并上传到 HDFS 中2.使用 Flume 监听整个目录的文件&#xff0c;并上传至 HDFS3…

【构造】Codeforces Round #843 (Div. 2) B Gardener and the Array

Problem - B - Codeforces题意&#xff1a;给定一个序列&#xff0c;让你判断是否存在两个子序列使得这两个子序列或起来相等思路&#xff1a;设两个子序列是a和b两个子序列凭空出现&#xff0c;那肯定考虑构造满足的条件是&#xff1a;a!bf(a)f(b)如果只考虑第二个条件&#x…

java系列文章之反射

文章目录一、动态语言二、反射机制概念三、反射的应用场合1. 编译时类型和运行时类型2. 编译时类型无法获取具体方法四、 反射 API五、反射使用步骤六、获取 Class 对象的 3 种方法七、创建对象的两种方法总结一、动态语言 动态语言&#xff0c;是指程序在运行时可以改变其结构…

读书:《5%的改变》

《5%的改变》 我们并不需要100%的改变&#xff0c;彻底推翻以前的旧习惯&#xff0c;对于绝大多数人来说&#xff0c;并不太现实&#xff0c;不如考虑一下只改变5%。 一天结束&#xff0c;22:00&#xff0c;开始为睡觉做准备&#xff0c;反思一下&#xff0c;发现今天好像什…

Pytorch LSTM实现中文单词预测(附完整训练代码)

Pytorch LSTM实现中文单词预测(附完整训练代码) 目录 Pytorch LSTM实现中文单词预测(词语预测 附完整训练代码) 1、项目介绍 2、中文单词预测方法&#xff08;N-Gram 模型&#xff09; 3、训练词嵌入word2vec&#xff08;可选&#xff09; 4、文本预处理 &#xff08;1&…

Java面向对象之继承

目录继承概述、使用继承的好处总结继承的设计规范、内存运行原理总结继承的特点总结继承后&#xff1a;成员变量、成员方法的访问特点总结继承后&#xff1a;方法重写继承后&#xff1a;子类构造器的特点总结继承后&#xff1a;子类构造器访问父类有参构造器总结this、super使用…

k8s之DaemonSet

写在前面 假定现在有一个这样的需求&#xff0c;需要收集每个Node的运行状态信息&#xff0c;并进行上报&#xff0c;假设有4个节点&#xff0c;我们可以使用Deployment 来实现吗&#xff1f;好像是可以的&#xff0c;我们只需要将repliacas设置为4不就行了&#xff0c;但是de…

怎样让公司全员贡献结构化内容?

- 1 - 问题 一个朋友在一个生产型企业的文档团队负责产品文档&#xff0c;他们使用DITA来编写各类文档&#xff0c;比如&#xff1a;公司管理文档、产品介绍、产品使用说明、产品安装手册等。 DITA 是基于XML的体系结构&#xff0c;用于编写、制作、交付面向主题的信息类型…

【NI Multisim 14.0 操作实例——音量控制电路】

目录 序言 一、音量控制电路 &#x1f34a;1.设置工作环境 &#x1f34a; 2.设置原理图图纸 &#x1f34a; 3.设置图纸的标题栏 &#x1f34a; 4.放置元器件 &#x1f34a; 5.编辑元器件属性 &#x1f34a; 6. 布局元器件 序言 NI Multisim最突出的特点之一就是用户界面…

数字IC设计、验证、FPGA笔试必会 - Verilog经典习题 (一)四选一多路器

数字IC设计、验证、FPGA笔试必会 - Verilog经典习题 &#xff08;一&#xff09;四选一多路器 &#x1f508;声明&#xff1a; &#x1f603;博主主页&#xff1a;王_嘻嘻的CSDN博客 &#x1f9e8;未经作者允许&#xff0c;禁止转载 &#x1f511;系列专栏&#xff1a; &#x…

Mercurius <11.5.0 存在拒绝服务漏洞(CVE-2023-22477)

漏洞描述 Mercurius 是NPM仓库中的开源组件&#xff0c;用作于 Fastify Web 框架的 GraphQL 适配器。 11.5.0 之前版本的 Mercurius 开启“订阅”功能时&#xff0c;任何 Mercurius 用户都可以通过 WebSocket 向 /graphql 端点&#xff08;如&#xff1a;ws://127.0.0.1:1337…

【屏幕驱动移植】点亮OLED屏幕并播放视频

写在前面 硬件软件准备: 名称备注屏幕SSD1106本文章所使用的的屏幕型号&#xff0c;仅仅作为驱动移植示例&#xff0c;其他型号的都可以按照本文的方法推广树莓派3B用于驱动屏幕&#xff0c;树莓派2B3B4B等型号都可以ESP32开发板用于驱动屏幕&#xff0c;具体是ESP32还是ESP32…

都2023年啦~用python来玩一次股票.....

人生苦短&#xff0c;我用python 这不是2023年已经来了吗&#xff1f; 总不能空着手回去吧&#xff1f; 这次简单用python来玩一下股票~ 本章源码更多电子书点击文末名片~ 准备工作 我们需要使用这些模块&#xff0c;通过pip安装即可。 后续使用的其它的模块都是Python自…

启动jeecg-boot框架(vue3版本)

jeecg-boot框架&#xff08;vue3版本&#xff09;一、简介二、项目启动1.前端模组&#xff1a;jeecgboot-vue3-master2.后端模组&#xff1a;jeecg-boot-master3.环境要求&#xff1a;4.数据库准备&#xff1a;5.前端启动&#xff1a;6.redis启动&#xff1a;7.后端启动&#x…

(Matlab实现)基于蒙特卡诺和拉格朗日乘子法的电动车调度【有序、无序充放电】

目录 1 概述 2 蒙特卡洛模拟方法介绍 3 拉格朗日乘子法 4 规模化电动汽车充电负荷预测计算方法 5 Matlab代码实现 1 概述 电动汽车EV(Electric Vehicle)具有清洁环保、高效节能的优点,不仅能缓解化石能源危机,而且能够有效地减少温室气体的排放。2015年10月&#xff0c;国…

Day 7 Spring 整合第三方框架

xml整合第三方框架有两种整合方案:不需要自定义名空间&#xff0c;不需要使用Spring的配置文件配置第三方框架本身内容&#xff0c;例如: MyBatis;需要引入第三方框架命名空间&#xff0c;需要使用Spring的配置文件配置第三方框架本身内容&#xff0c;例如: Dubbo.1 整合MyBati…

Apollo星火计划学习笔记——Control 专项讲解(PID)

文章目录1. PID算法介绍1.1 时间连续与时间离散1.2 位置式与增量式1.3 PID算法扩展2. PID调试方法3. APOLLO代码介绍3.1 PID算法3.2 积分饱和问题3.3 纵向控制代码3.3.1 构造函数3.3.2 加载各种纵向控制的配置参数3.3.3 二阶巴特沃斯低通滤波器《数字信号处理》3.3.4 插值出油门…

PMP考试是什么?适合哪些人来学呢?

PMP&#xff0c;根据PMI的解释&#xff0c;就是项目管理专业人士资格认证&#xff0c;全称如下图&#xff1a;PMP考试是由PMI发起、组织和出题&#xff0c;严格评估项目管理专业人士知识技能是否具有高品质的资格认证考试。PMI&#xff1a;美国项目管理协会&#xff08;Project…

【小米路由器3】breed刷机救砖-nand flash硬改SPI flash-编程器救砖(解决ttl无法救砖问题)

大家好&#xff0c;我是老子姓李&#xff01;&#xff08;gzh&#xff1a;楠瘦&#xff09; 本博文带来【小米路由器3】变砖&#xff0c;ttl无法救砖&#xff0c;硬改焊接一块SPI flash&#xff0c;使用编程器刷入小米路由器mini的breed最终成功救砖。 目录1.引言1.1 背景1.2回…

07MEMS传感器技术 讲座

把同步现象应用于传感器设计。 什么是MEMS&#xff1f; 1.mems芯片是什么意思 MEMS是Micro-Electro-Mechanical System的缩写&#xff0c;中文名称是微机电系统。MEMS芯片简而言之&#xff0c;就是用半导体技术在硅片上制造电子机械系统&#xff0c;再形象一点说就是做一个微…