目录
参考链接
入门学习视频:
【YouTube高赞中英字幕】4个小时 Lua完整教程 从入门到高级_哔哩哔哩_bilibili
环境配置参考:
VSCode 配置 Lua 开发环境(清晰明了)_lua vscode-CSDN博客
1. 基本输出和注释
1.1. 基本输出
-- print输出,自动换行
print("hello world")
-- ','分隔会对输出制表操作
print("dsadasd","dasdasd")
-- '..' 表示拼接
print("dasda" .. "dasd ")
-- 转义字符包括 \n \t \v \\ \"等等
print("hello\nWorld")
1.2. 注释
-- 两个短破折号表示单行注释
--[[
随后跟两个中括号表示多行注释
注意第二个破折号和第一个左中括号之间不能有空格
]]
2. 数据类型和变量
2.1. 数据类型
- nil 表示空值
- number 表示数字,包括整数和浮点数,如
3, 3.14
- string 字符串,可以用''或""表示,如
'hello'
"world"
- boolean 表示布尔变量,包括
true
和false
-
- 只有
false
和nil
结果为false
- 其他包括
0
""
的结果都为true
- 只有
- table 后面table章节详解
tonumber(string)
和tostring(number)
可以实现number
和string
的转化
2.2. 变量
lua的变量弱类型,不需要提前规定类型名,并且变量的类型可以修改
-- local varname 创建局部变量
local var -- 默认为nil
local name = 'jack'
name = 18 -- 变量类型可以修改
-- 创建全局变量
-- 1. 直接用varname创建
-- 2. 用_G.varname创建
-- ps: 通常全局变量首字母大写
C = nil
_G.Str = "hello"
-- 多个变量可以依次命名和定义
local x,y,z = 1, 2, 3
-- type(varname)可以获得变量的类型
print(type(x)) -- number
3. 数学计算
-- 基本运算包括 + - * / % ^
-- 此外还有math库,包括大部分数学运算函数
-- 如max, min, floor, ceil...
-- math包括随机数
math.randomseed(os.time()) -- 随机数种子
math.random() -- 生成[0,1]的随机数
math.random(1,10) -- 生成[1,10]的随机数
4. string
4.1. 多行字符串
-- 用[[]]来包括
-- 会考虑字符前面的占位符
-- ]]
name = [[
hello
world
]]
4.2. string的函数
-- #strname 或 string.len(strname)得到长度
print(#str)
-- tostring(number)把number转为string
tostring(22)
-- string.lower(strname) 转小写
-- string.upper(strname) 转大写
-- string.sub(strname, start, end)取子串,参数分别是串名、开始索引和结束索引
print(string.sub(str,2,3))
-- string.char(number)从ASCII码转为字符
print(string.char(65))
-- string.rep(strname,time,分隔符)把字符串重复time次,然后用分隔符进行分隔
print(string.rep(str,10,','))
-- string.format() c风格书写
print(string.format("pi:%.2f\nMy age: %i",math.pi,18))
-- string.find(strname,要查找的字符串),返回在原串的开始索引
print(string.find(str,"el"))
-- string.match(strname,要匹配的字符串)返回能被匹配的子串
print(string.match(str, "el"))
-- string.gsub(strname,匹配字符串,替换字符串),把字符串的匹配字符串换成替换字符串
print(string.gsub(str,'e','wow'))
5. if语句
-- 只有nii和false会得到false,其他都是true
-- lua 中不等于是 ~=
-- 关系运算符包括 and, or, not
-- if语句
-- if 条件 then 执行语句 end
local age = 18
if age > 17 and age < 60 then
print("suitable!")
end
-- if-else语句
-- if 条件 then 执行语句
-- elseif 条件 then 执行语句
-- else 执行语句
-- end
if age > 17 then
print("if statement")
if type(age) == 'number' then
print("if in if")
end
elseif age > 10 then
print("elseif statement")
else
print("else statement")
end
6. 循环语句
注意:lua的任何索引都是从1开始
6.1. for loop
for i = 1, 10, 1 do
print(i)
end
-- 等价于 for (i = 1; i <= 10; ++i)
-- 其中step可以省略,默认为1
-- 可以逆向循环,把step设为负值即可
for i = 10,1,-1 do
print(i)
end
6.2. while loop
-- while 条件判断 do
-- 执行语句
-- end
while count > 0 do
print(count)
count = count - 1
end
6.3. do while loop
-- repeat
-- 执行语句
-- until 终止条件
local t = 1
repeat
print(t)
t = t + 1
until t > 10
7. 用户输入
-- io.read()读取用户输入
local res = io.read()
print(res)
-- io.write()执行不换行输出
io.write("hello world")
8. table
8.1. table的创建
-- 用varname = {}来创建table
-- table内可以有多个元素
-- 每个元素的类型可以各不相同
local arr = {10, true, "hello", 2,4}
8.2. table的遍历
-- #获取table的长度
-- [index]对元素进行访问
-- 可以用for遍历table
for i = 1, #arr do
-- 执行语句
end
-- 键值对的for循环,其中key是索引,value是值,t是table
for key, value in pairs(table) do
-- 执行语句
end
8.3. table的函数
-- table.sort(table_name) 对table进行排序
local nums = {4322,54,123,7567,0,31,4,56}
table.sort(nums)
-- table.insert(tablename,index,value)
-- 在table的第index的位置插入value
table.insert(nums,2,'lol')
-- table.remove(tablename, index)
-- 删除table的index位置的元素
table.remove(nums,5)
-- table.concat用分隔符连接table
print(table.concat(nums, '?'))
8.4. 多维table
-- 定义多维table
local arrs = {
{1, 2, 3},
{4, 5, 6},
{7, 8, 9}
}
-- 使用下标访问
print(arrs[1][1])
-- 遍历多维table
for i=1,#arrs do
for j = 1, #arrs[i] do
print(arrs[i][j])
end
end
9. 函数
9.1. 函数的定义
-- 函数分为局部和全局
-- 局部定义为local,全局就是不加修饰
local function display(var)
print(var)
end
--函数的另一种定义法,将函数名写在前面
local display = function(var)
print(var)
end
9.2. 函数的特性
-- 默认参数:在函数体里面写var = var or defaultval
local function getAge(age)
age = age or 5 -- 默认参数为5
print(age)
end
getAge()--默认参数为5
-- 函数体内定义的全局变量作用域外可以访问
local function func(i)
Y = i -- 全局变量,作用域外可以访问
end
func(7)
print(Y)
-- return 返回参数
local function sum(num1, num2)
return num1 + num2
end
-- 多值返回与接收
local function twoRet(num1, num2)
return num1, num2
end
local n1, n2 = twoRet(9, 0)
9.3. 递归
-- 在函数体内调用自己
local function jiecheng(num)
if num == 1 then
return 1
end
return num * jiecheng(num - 1)
end
9.4. 匿名函数
local function func()
return function () -- 返回了一个匿名函数
return 10
end
end
local x = func() -- 此时x是函数
9.5. 不定长参数
-- 参数列表传入'...'表示不定长参数
-- 如果要对不定长参数进行遍历,需要添加{...}将其变成table
local function sum(...)
for key, value in pairs({...}) do --用中括号把可变参数变成table
print(key,value)
end
end
sum(2,3,5,7,11)
10. co-routines
协程使多个函数可以以自定义的方式交替执行
-- coroutine.create(function or 匿名函数)
-- 创建协程
-- coroutine.status(coroutine_name)
-- 得到该协程状态
-- "running" 正在运行
-- "suspended" 挂起或还没有开始运行
-- "normal" 是活动的,但没有运行
-- "dead" 运行完或因错误停止
-- coroutine.yield()
-- 挂起当前协程
-- coroutine.resume(coroutine_name)
-- 继续或开始一个协程
-- 创建协程1
local routine_1 = coroutine.create(
function ()
for i = 1, 10, 1 do
print("Routine 1: " .. i)
if i == 5 then
-- 此时挂起协程1
coroutine.yield()
end
end
end
)
local routine_func = function ()
for i = 11, 20, 1 do
print("Routine 2: " .. i)
end
end
-- 创建协程2
local routine_2 = coroutine.create(routine_func)
-- 运行协程1
coroutine.resume(routine_1)
print(coroutine.status(routine_1)) -- 此时协程1挂起
coroutine.resume(routine_2) -- 运行协程2
-- 启动协程1
if coroutine.status(routine_1) == 'suspended' then
coroutine.resume(routine_1)
end
print(coroutine.status(routine_1)) --协程1执行完毕
11. files
-- io.output(filename) 创建文件并选中,如果已存在会清空
-- io.write(内容) 向被选中的文件中写入内容
-- io.close()关闭当前被选中的文件
io.output("myFile.txt")
io.write("hello")
io.close()
-- io.input(filename)读取并选中文件
-- io.read(number)读取前number个字符
-- io.read(var)按照var的方式进行读取
-- "n" 读取一个数字,根据lua的转换文法返回浮点数或整数
-- "a" 从当前位置开始读取整个文件
-- "l" 读取一行并忽略行结束标记
-- "L" 读取一行并保留行结束标记
-- io.read()是按照指针操控的顺序读
io.input("myFile.txt")
local file = io.read(5)
local num = io.read("l")
io.close()
print(file)
print(num)
-- 可以直接用io.open访问文件,然后选择模式
-- 模式包括读、写、追加等
-- 'a'表示追加,可以在文件末尾追加内容
local file = io.open("myFile","a")
--此时要用file:来控制对文件对象的操作
io.write("hahaha") -- 错误
file:write("hahaha") --正确
--此时关闭文件要用file:close
file:close()
12. os module
-- time: 如果不传参就是1970到现在,否则就是1970到参数的时间
print(os.time({
year = 2000,
month = 10,
day = 20,
hour = 13,
min = 20,
sec = 10
}))
-- os.difftime(两个时间变量) 返回时间差
-- os.date() 返回日期
-- os.rename(文件名, 新名字) 重命名文件
-- os.remove(文件名) 删除文件
-- os.execute(指令字符串) 在终端执行指令
-- os.clock() 计时
local start = os.clock()
-- 执行操作
local ended = os.clock()
print(ended - start)
-- os.exit() 退出程序
13. custom modules
创建.lua文件,然后编写自己的module,随后在主程序代码中用require()函数引入module
-- modules返回的是一个table
-- 把要实现的函数体放在table体内,用tablename.funcname表示
-- 函数必须是全局函数,因为要在其他地方使用
_G.mmath = {}
-- 定义为mmath表的内容
function mmath.add(x, y)
return x + y
end
function mmath.power(num1, num2)
return num1 ^ num2
end
return mmath
local mod = require("MyMath")
print(mod.add(1,5))
print(mod.power(2,6))
14. 面向对象编程
lua不是面向对象语言,但是我们可以用table和函数来模拟面向对象
14.1. 定义一个对象
local t = {
name = "Jack",
age = 18,
friend = {"Fred"}
}
print(t.name) -- 访问对象的属性
14.2. 创建一个类
-- 写成一个返回table的函数
-- 其中类名就是函数名
-- 返回匿名table
-- 返回值前面可以定义默认参数
-- self可以访问table的元素
local function Pet(name)
name = name or "Luis" --默认参数
return {
name = name, -- 定义属性
status = "hungry",
feed = function(self) -- 定义成员函数
self.status = "full"
end
}
end
local cat = Pet("Kitty")
print(cat.status) --用dot 访问变量
cat:feed() -- 用:访问函数
关于使用冒号和点号的区别,可以参考理解Lua中点号和冒号的区别及适用场合_lua冒号换成点-CSDN博客
14.3. 类的继承
-- 定义函数续写table
-- 函数名即为派生类的名字
-- 最后返回值依然是table
local function Dog(name, breed)
local dog = Pet(name) -- 获得table
dog.breed = breed -- 续写table的属性
dog.loyalty = 0
dog.isLoyal = function (self) --定义函数
return self.loyalty >= 10
end
dog.bark = function (self)
print("Woof Woof")
end
--重写函数
dog.feed = function (self)
self.status = "full"
self.loyalty = self.loyalty + 10
end
return dog
end
local lassy = Dog("Lassy", "Poodle")
lassy:feed()
if lassy:isLoyal() then
print("good dog")
else
print("bad dog")
end
15. metamethods 运算符重载
-- 定义一个table叫metatable,然后在里面对运算符进行重写
-- 左边是运算符的表示,右边是函数体,可以是正常函数,也可以是匿名函数
--运算符表示如下:
--[[
__add = +
__sub = -
__mul = *
__div = /
__mod = %
__pow = ^
__concat = ..
__len = #
__eq = ==
__lt = <
__le = <=
__gt = >
__ge = >=\
......
]]
-- 然后使用setmetatable(要重载的table,metatable)函数来进行重载
local metatable = { -- 定义如何重写
__add = function (x,y) -- 用匿名函数定义重写形式
return x.num + y.num
end,
__sub = function (x,y)
return x.num - y.num
end
}
local tbl1 = {num = 50}
local tbl2 = {num = 40}
setmetatable(tbl1, metatable) -- 绑定tbl1进行重写
print(tbl1 + tbl2)
print(tbl1 - tbl2)