Sublime 编辑器
注意:在保存lua文件时,必须是<文件名.lua>的形式,必须加.lua后缀名
执行脚本:Ctrl + B
清空执行结果区:全选 + 删除
Lua语句
Lua语言是区分大小写的
Lua语句不需要使用分号结尾, 但是即使写了分号也不保错
Lua注释
单行注释:-- (sublime快捷键:ctrl+/)
多行注释: --[[ 语句 ]] (sublime快捷键:ctrl+shift+/)、--[[ 语句 ]]--、--[[ 语句 --]]
--单行注释
--print("11111111111")
--多行注释
--[[
print("22222222222")
print("33333333333333")
]]
--[[
print("22222222222")
print("33333333333333")
]]--
--[[
print("22222222222")
print("33333333333333")
--]]
多行注释推荐使用 --[=[注释内容]=]
print("44444444444444444")
Lua变量定义
变量名 = 初始值
无需指定数据类型, 会根据赋值的值自动改变变量的数据类型
-- C# 数据类型 变量名 = 初始值
c1 = [[abcdefg]]
print(c1, type(c1))
变量名(标识符)规范
1、以字母或下划线开头
2、后面可以有数字、字母、下划线组成
3、尽量避免 下划线+大写字母 开头的写法,lua自身保留格式
查看变量类型
type(变量名)
num = 10.1
print(num, type(num))
Lua数据类型
number数字类型
lua不区分整数与小数, 数都是number类型
num = 10.1
print(num, type(num))
num2 = 10
print(num2, type(num2))
nil空数据
等同于null
nil可以使用在条件判断中,表示false结果
boolean布尔类型
ture 或者 false
lua认为只有false和nil是假的(不满足条件), 其他都是真的(满足条件)
string字符串类型
Lua没有字符类型, 双引号与单引号都表示字符串类型
"字符内容":不可以换行编辑
'字符串内容':不可以换行编辑
[[字符串内容]]:可以换行编辑,容易与多行注释冲突
字符串的基本操作
数学运算符 +、-、*、/、%
当两个字符串进行数学运算符运算时,会将两个字符串转换成数值进行计算,如果转换失败就报错
str1 = "5"
str2 = "7"
print("--------------------------字符的数学运算------------------------------")
str3 = str1 + str2
str4 = str1 - str2
str5 = str1 * str2
str6 = str1 / str2
str7 = str1 % str2
print(str3)
print(str4)
print(str5)
print(str6)
print(str7)
字符串的连接
使用“..” 两个点进行拼接
print("-----------------------------字符串的连接-----------------------------")
str8 = str1 .. str2
print(str8)
字符串的长度
#变量名
print("----------------------字符串的长度------------------------")
str9 = "12345asgfasfd"
length = #str9
print(length)
str10 = [[12345a
sgfasfd]]
length = #str10
print(length)
Lua运算符
算术运算符
+, -, *, /, %
print(1 + 2)
print(4 % 2)
^:幂次方
2 ^ 3表示2的3次方
print(2 ^ 3)
关系运算符
<,>,<=,>=,==,
print(1 > 2)
~=:不等判断,与C#不一样
print(1 ~= 2)
逻辑运算符
and:与
同时为真才为真,相当于C# &&
print(true and true)
print(false and true)
or:或
只要有一个为真就为真,相当于C# ||
print(false or true)
not:非
取反,相当于C# !
print(not true)
流程控制语句
if 条件 then 语句 end
--num为nil, lua认为nil为false
if not num then
print("num为nil")
end
year = 2004
--1 能被4整除,不能被100整除
--2 能被400整除
if (year % 4 == 0 and year % 100 ~= 0) or year % 400 == 0 then
print("year: "..year.." 是闰年")
end
if 条件 then 语句1 else 语句2 end
-- if else
age = 19
if age > 18 then
print("你已经成年了")
else
print("你未成年")
end
if 条件1 then 语句1 elseif 条件2 then 语句2 else 语句3 end
-- if else if else
--判断字符串是否是A或B ,如果是A打印 A1,如果是B打印B2, 如果都不是,打印C3
str = "9"
if str == "A" then
print("A1")
--elseif是放在一起写的,中间没有空格, 只要是条件判断,条件后要加then关键字
elseif str == "B" then
print("B2")
else
print("C3")
end
循环语句
while
--[[
C# :
while(循环条件)
{
循环体
}
]]
--[[
Lua:
while 循环条件 do
循环体
end
]]
num = 37
--判断num是否是质数, 只能被1和本身整除的数就是质数
print("判断num是否是质数, 只能被1和本身整除的数就是质数")
isPrime = true
i = 2
while i < num do
if num % i == 0 then
isPrime = false
--可以跳出
break
end
i = i + 1
end
if isPrime then
print("num: "..num .."是质数")
else
print("num: "..num .. "不是质数")
end
--打印100到999之间的水仙花数
--153 = 1*1*1 + 5*5*5 + 3*3*3
print("打印100到999之间的水仙花数")
num = 100
while num < 1000 do
--取个位,十位,百位
one = num % 10;
tow = (num - one) / 10 % 10
-- (153 - 3 - 5 * 10) / 100
three = (num - one - tow * 10) / 100
if one^3 + tow^3 + three^3 == num then
print(num)
end
num = num + 1
end
repeat
--[[
C#:
do
{
循环体
}while(循环条件)
满足条件循环
]]
--[[
lua:
repeat
循环体
until 跳出循环条件
满足条件退出循环
]]
num = 10
repeat
print(num)
num = num - 1
--注意条件是跳出循环的条件
until num >= 1
for
--[[
C#
for(int 变量 = 初始值; 循环条件; 增量表达式)
{
循环体
}
]]
--[[
Lua
for 变量 = 初始值, 阈值, 增量值 do
循环体
end
变量超过阈值,结束循环,
每次循环变量都增加增量值
增量值可以省略,如果省略那么默认是1
]]
--打印2到100之间的质数,包含2和100
for num = 2,100 do
isPrime = true
for i = 2, num-1 do
if num % i == 0 then
isPrime = false
end
end
if isPrime then
print(num)
end
end
--打印2000年到2050年之间的所有闰年
for year = 2000, 2050 do
if (year % 4 == 0 and year % 100 ~= 0) or year % 400 == 0 then
print(year)
end
end
注意:lua的循环语言可以使用break跳出,但是没有continue
Lua中的数组
lua 中没有数组的,是使用表table结构来模拟数组, 长度不是固定的
lua数组的默认索引是从1开始的,不是从0,遇到非连续的索引后就停
--[[
C#
数据类型[] 数组名 = new 数据类型[数组的长度]
]]
--[[
lua 中没有数组的,是使用表table结构来模拟数组, 长度不是固定的
数据名 = {}
]]
array1 = {}
--可以初始化赋值
array2 = {"123", "456"}
--打印第1个数组元素
print(array2[1])
--数组的长度
print(#array2)
--遍历数组
for i = 1, #array2 do
print(array2[i])
end
--对第5个索引赋值为“789”
array2[5] = "789"
--数组的长度
print("数组长度: "..#array2)
--这种写法在语法上没有错误,但是主管不认为是数组
array3 = {[-1] = "45678", [0] = "123", [1] = "456"}
print(array3[-1])
print(array3[0])
--数组的长度
print("数组长度: "..#array3)
--将10 - 1 依次存储到一个数组中
arr = {}
index = 1
for num = 10, 1, -1 do
arr[index] = num
index = index + 1
end
for i = 1, #arr do
print(arr[i])
end
函数
先定义,再执行
-- 函数的定义
--[[
function 函数名(参数列表)
end
]]
--[[
函数名 = function(参数列表)
end
]]
function Func1()
print("执行Func1的方法")
--该位置调用,只要保证Func1调用时在Func2定义之后就可以
Func2()
end
--调用会报错, 因为Func2在该行执行时未定义
--Func2()
Func2 = function()
print("Func2")
end
Func1()
--带有参数与返回值的,注意参数列表无需指定类型
function Func3(a, b)
sum = a + b
return sum
end
sum = Func3(10, 20)
print(sum)
--多个返回值
function Func4()
return 1, "str", true, {"abc", "def"}
end
--接收多个返回值的函数,要使用多个变量接收
one, tow, three, four = Func4()
print(one)
print(tow)
print(three)
print(four[1])
--lua函数还支持可变参数 ...
function Func5(...)
--通过数组获取可变参数
--[[
args = {...}
for i = 1, #args do
print(args[i])
end
]]
--第二种获取可变参数的方式, arg是lua方法中默认的可变参数组
for i = 1, #arg do
print(arg[i])
end
print("Func5")
end
Func5(1,"334", true, {"abc", "def"})
表(table)
lua中的table是一个关联数组, 索引可以是数字也可以是字符串
--定义
tab1 = {}
tab2 = {[1] = "123", ["Key"] = 34, Name = "小明"}
--赋值访问
print(tab2[1])
tab2["Name"] = "小李"
tab2.Name = "小红"
--访问字符串索引的元素
print(tab2["Name"])
print(tab2.Name)
print(tab2["Key"])
print(tab2.Key)
-- 释放
tab2 = nil
print("----------------------------------------------------------")
--表中存储方法
tab3 =
{
Func1 = function(a)
print("Func1: " .. type(a))
print(a)
end
}
tab3.Func2 = function(a)
print("Func2: " .. type(a))
end
--调用表中的方法
--当使用:调用表中初始化时方法或通过表.方法名定义的方法时, 会将表作为第一个参数传递到方法中
--当使用 . 调用表中初始化时方法或通过表.方法名定义的方法时, 不会将表传入
tab3:Func1()
print(tab3)
tab3:Func2()
print("=======================================================")
function tab3:Func3(a)
print("Func3: " .. type(a))
print("self: " .. type(self))
end
--当调用使用 表:方法名 定义的方法时
-- 表.方法()调用, 表示不传入当前表
-- 表:方法()调用, 表示传入当前表, 不占参数位置,通过self可以获取表
tab3:Func3()
模块化开发
require 函数
require("<模块名>")
TestModel引用其他文件
--执行Model.lua的文件
local m = require("Model")
print("-----------------------------------------------------------------")
print(m.Name)
print(m.Age)
m:Show()
print("-----------------------------------------------------------------")
--执行Model1.lua的文件, 注意Model1在当前文件文件夹的子文件夹Lesson下
require("Lesson/Model1") -- Lesson/Model1 表示相对路径,相对于当前文件所在文件夹的路径
--执行文件都有一个加载路径, 加载路径都存储在table表 package.path中
--路径与路径间使用分号分隔,后缀是.lua,通过?来匹配文件名
print(type(package.path))
--执行Model3.lua的文件, 注意Model3在D盘的TestLua文件夹下
--需要将桌面路径添加到 package.path 中,文件路径以 ";" 号分隔,最后的 2 个 ";;" 表示新加的路径后面加上原来的默认路径。
package.path = package.path .. ";D:/TestLua/?.lua"
require("Model3")
print("========================================================================")
tab = {"123", "234", "456", "567"}
local Json = require("JsonUtility")
--将表解析成Json串
str = Json.encode(tab)
print(str)
Model
print("Start Model ......")
local Model = {}
Model.Name = "小明"
Model.Age = 18
function Model:Show()
print("我叫:" .. self.Name .. ", 我的年龄: " .. self.Age .. "岁")
end
return Model
元表
算术类
+:__add
--元表, 针对table的, 元表是改变表与表间的运算或操作的规则的
t1 = {key = "123", age = 18}
t2 = {name = "456", [-1] = "abc", [1] = "ghj", [2] = "fhgdsh", [4] = "asdfasdf"}
add =
{
--合并两个表为一个新的表
__add = function (tab1, tab2)
local tab = {}
--遍历tab1
for k,v in pairs(tab1) do
tab[k] = v
end
--遍历tab2
for k,v in pairs(tab2) do
tab[k] = v
end
return tab
end
}
--设置meta表为t1表的元表
--setmetatable(t1, meta)
setmetatable(t1, add)
--当两个表向加运算时,先判断两个表是否有元表,如果都没有元表,直接报错
--如果其中一个有元表,再判断元表中是否有 __add 的元方法,如果没有,直接报错
--如果有元表并且有__add元方法, 那么执行__add的元方法, 该方法的返回值就是两个表相加的结果
--执行__add元方法时,将 + 号左边的表作为第一个参数传入, 将+号右边的表作为第二个参数传入
t3 = t1 + t2
--print("t1", t1)
--print("t2", t2)
print(t3)
for k,v in pairs(t3) do
print(k,v)
end
-:__sub
*:__mul
/:__div
比较类
等于:__eq
设置元表
mytable = {} -- 普通表
mymetatable = {} -- 元表
setmetatable(mytable,mymetatable) -- 把 mymetatable 设为 mytable 的元表
__index 元方法
这是 metatable 最常用的键。
当你通过键来访问 table 的时候,如果这个键没有值,那么Lua就会寻找该table的metatable(假定有metatable)中的__index 键。如果__index包含一个表格,Lua会在表格中查找相应的键。
> other = { foo = 3 }
> t = setmetatable({}, { __index = other })
> t.foo
3
> t.bar
nil
如果__index包含一个函数的话,Lua就会调用那个函数,table和键会作为参数传递给函数。
__index 元方法查看表中元素是否存在,如果不存在,返回结果为 nil;如果存在则由 __index 返回结果。
mytable = setmetatable({key1 = "value1"}, {
__index = function(mytable, key)
if key == "key2" then
return "metatablevalue"
else
return nil
end
end
})
print(mytable.key1,mytable.key2)
实例输出结果为:
value1 metatablevalue
__newindex 元方法
__newindex 元方法用来对表更新,__index则用来对表访问 。
当你给表的一个缺少的索引赋值,解释器就会查找__newindex 元方法:如果存在则调用这个函数而不进行赋值操作。
mymetatable = {}
mytable = setmetatable({key1 = "value1"}, { __newindex = mymetatable })
print(mytable.key1)
mytable.newkey = "新值2"
print(mytable.newkey,mymetatable.newkey)
mytable.key1 = "新值1"
print(mytable.key1,mymetatable.key1)
输出结果为:
value1
nil 新值2
新值1 nil
以上实例中表设置了元方法 __newindex,在对新索引键(newkey)赋值时(mytable.newkey = "新值2"),会调用元方法,而不进行赋值。而如果对已存在的索引键(key1),则会进行赋值,而不调用元方法 __newindex。