热更新解决方案2 —— Lua语法相关知识点
概述
开发环境搭建
Lua语法
1.第一个Lua程序
2.变量
print("******变量*******");
--lua当中的简单变量类型
-- nil number string boolean
-- lua 中所有的变量声明 都不需要声明变量类型 它会自动的判断类型
-- 类似C# 中的var
--lua中的一个变量 可以随便赋值 —— 自动识别类型--通过type 函数 我们可以得到变量的类型
-- type 的返回值是 string--lua中使用没有声明过的变量
--不会保错 默认值 是nil
print(b)--nil 有点类似 C#中的null
print("******nil*******");
a = nil
print(a)
print(type(a))
print(type(type(a)))--number 所有的数据都是number
print("*******number*******")
a = 1
print(a)
a = 1.2
print(a)
print(type(a))print("*******string*******")
a = "123"
print(a);
print(type(a))
--字符串的声明,使用单引号或者双引号包裹
--lua里 没有char
a = '123'
print(a)
print(type(a))print("*******boolean*******")
a = true
print(a)
a = false
print(a)
print(type(a))--复杂数据类型
--函数 function
--表 table
--数据结构 userdata
--协同程序 thread(线程)
3.字符串操作
print("******字符串*******")
str = "双引号字符串"
str = '单引号字符串'--获取字符串的长度
print("*******字符串长度**********")
s = "Sun木兮"
--一个汉字占3个长度
--英文符号 占1个长度
print(#s)print("*******字符串多行打印*******")
--方式一
--lua中也是支持转义字符的
print("123\n123")--方式二
s = [[山有
木兮
木有
枝]]
print(s)
print([[心悦
君兮君]])print("*******字符串拼接*******")
--方式一
--字符串拼接 通过..
print("123" .. "456")
s1 = "111"
s2 = 222
print(s1 .. s2)
s1 = 111
s2 = 222
print(s1 .. s2)--方式二
print(string.format("山有木兮, 木%d", 67))
--%d: 与数字拼接
--%a: 与任何字符串拼接
--%s: 与字符串配对
--...print("*******别的类型转字符串*******")
a = true;
print(tostring(a))print("*******字符串提供的公共方法*******")
str = "abCdeFg"
--小写转大写的方法
--该方法不会改变原字符串,之后返回一个新字符串 (string大部分都不会改变原字符串)
print(string.upper(str))
print(str)
--大写转小写
print(string.lower(str))
--翻转字符串
print(string.reverse(str))
--字符串索引查找
print(string.find(str, "Cde")) --3 5
print(string.find(str, "C")) -- 3 3
--截取字符串
print(string.sub(str, 3)) --CdeFg
print(string.sub(str, 3, 4)) --重载方法
--重复字符串
print(string.rep(str, 1)) --返回的是原字符串
print(string.rep(str, 2)) --abCdeFgabCdeFg 返回两遍字符串
--字符串修改
print(string.gsub(str, "Cd", "**")) -- 返回 ab**eFg 1 1代表修改的次数
str = "abCdeFgCd"
print(string.gsub(str, "Cd", "**")) -- 返回 ab**eFg** 2--字符转 ASCII码
a = string.byte("Lua", 1) --将字符串里的一个指定位置转为ASCII码
print(a)
--ASCII码 转字符
print(string.char(a))
4.运算符
print("*******运算符********")print("*******算术运算符********")
-- 只有 + - * / % ^(幂运算)
-- 没有自增自减 ++ --
-- 没有复合运算符 += -= /= *= %=
-- 字符串 可以进行 算数运算符操作 会自动转成 number--加法
print("加法运算" .. 1 + 2)
a =1
b = 2
print(a + b)
print("123" + 1) -- 输出:124
print("123.4" + 1) -- 输出:124.4--减法
print("减法运算" .. 1 - 2) -- 输出 -1
print("123.4" - 1) -- 输出: 122.4--乘法
print("乘法运算" .. 1 * 2)
print("123.4" * 2) -- 246.8--除法
print("除法运算" .. 1 / 2) -- 0.5
print("123.4" / 2) -- 61.7--取余
print("取余运算" .. 1 % 2) -- 1
print("123.4" % 2) -- 1.4--幂运算
-- ^ 在lua中 该符号是幂运算 而在C#中^是异或
print("幂运算" .. 2 ^ 5)
print("123.4" ^ 2)print("*******条件运算符********")
-- > < >= <= == ~=(不等于,C#中是!=)
print(3>1)
print(3<1)
print(3>=1)
print(3>=1)
print(3==1)
print(3~=1)print("*******逻辑运算符********")
-- 逻辑与 C#中 && 逻辑或 C#中 || 取反 C#中 !
-- Lua中 与:and 或:or 非:not 在lua中and、or也支持短路
print(true and false) -- false
print(true and true) -- tureprint(true or false) -- true
print(false or false) -- falseprint(not true) -- falseprint("********短路测试*********")
print(false and print("123")) -- 输出 false
print(true and print("123")) -- 输出: 123 nilprint("*******位运算符********")
-- & | lua中不支持位运算符 需要我们自己实现print("*******三目运算符********")
-- lua中也不支持三目运算符
5.条件分支语句
print("***********条件分支语句************")
a = 9
-- if 条件 then...end
--单分支
if a > 5 thenprint("124")
end--双分支
--if 条件 then...else...end
if a < 5 thenprint("123")
elseprint("321")
end--多分支
--if 条件 then...elseif 条件 then...elseif 条件 then...else...end
if a < 5 thenprint("123")
--lua中 elseif 一定是连着写的 否则会报错
elseif a == 6 thenprint("6")
elseif a == 7 thenprint("7")
elseif a == 8 thenprint("8")
elseif a == 9 thenprint("9")
elseprint("other")
end-- 组合条件的使用
if a >= 3 and a <= 9 thenprint("3到9之间")
end-- Lua中没有switch 需要的话可以自己实现
6.循环
7.函数
print("********函数*******")
--function 函数名()
--end--a = function()
--endprint("********无参数无返回值*******")
-- F1() -- 不能在一个函数声明之前去调用它
function F1()print("Fi函数")
end
F1()-- 有点类似 C#中 委托和事件
F2 = function()print("F2函数")
end
F2()print("********有参数*******")
function F3(a)print(a)
end
F3(1)
F3("123")
F3(true)
-- 如果你传入的参数 和函数参数个数不匹配
-- 它不会报错 只会补空nil 或者丢弃
F3()
F3(1,2,3)print("********有返回值*******")
function F4(a)return a, "123", true
end
-- 多返回值时 在前面声明多个变量来接即可
-- 如果变量不够 不影响 值会接取对应位置的返回值
-- 如果变量多了 也不影响 多出的直接赋值nil
temp, temp2, temp3 = F4("1")
print(temp)
print(temp2)
print(temp3)print("********函数的类型*******")
-- 函数类型 就是 function
F5 = function()print("123")
end
print(type(F5))print("********函数的重载*******")
--函数名相同 参数类型不同 或者参数个数不同
--luaz中 函数不支持重载
--默认调用的是最后一个申明的这个函数
function F6()print("F6_1")
end
function F6(str)print(str)
endF6() -- 输出 ilprint("********变长参数*******")
function F7(...)--变长参数使用 用一个表存起来 再用arg = {...}for i = 1,#arg doprint(arg[i])end
end
F7(1,"123",true,4,5,6,7)print("********函数嵌套*******")
--function F8()
-- F9 = function()
-- print("123")
-- end
-- return F9
--end-- 简洁写法
function F8()return function()print("123")end
endf9 = F8()
f9()--Lua 中闭包的体现
function F9(x)--改变传入参数的生命周期return function(y)return x + yend
endf10 = F9(10)
print(f10(5))
8.复杂数据类型 —— 表
print("*********复杂数据类型 table***********")
--所有的复杂类型都是table(表)print("*********数组***********")
a = {1,2,3,4,"1231",true,nil}
--lua中 索引从1开始
print(a[0]) -- 输出 nil 超出索引不会报错
print(a[1]) -- 输出 1
print(a[5])
print(a[6])
print(a[7])
--# 是通用的获取长度的关键字
--在打印长度的时候 空被忽略
--如果表中(数组中)某一位变成nil 会影响#获取的长度
print(#a) -- 输出 6 第7位是nil所以会被忽略
--a = {1,2,nil,4,"1231",true,nil}
--print(#a) -- 输出 2print("*********数组的遍历***********")
for i = 1,#a doprint(a[i])
endprint("*********二维数组***********")
--注意 其实lua中是没有二维数组的概念的 只是我们用表体现出数组、二维数组、字典的特征
a = {{1,2,3},{4,5,6}}
print(a[1][1]) -- 第一个表
print(a[1][2])
print(a[1][3])
print(a[2][1]) -- 第二个表
print(a[2][2])
print(a[2][3])print("*********二维数组的遍历***********")
for i = 1,#a dob = a[i]for j = 1,#b doprint(b[j])end
endprint("*********自定义索引***********")
-- 不建议自定义索引
aa = {[0] = 1,2,3, [-1] = 4,5}
print(aa[0])
print(aa[-1])
print(aa[1])
print(aa[2])
print(aa[3])
print(#aa)
9.迭代器遍历
10.复杂数据类型 —— 表
字典
print("*************复杂数据类型——表2*****************")
print("******字典*****")
print("******字典的申明*********")
--字典是由键值对构成
a = {["name"] = "Sunset", ["age"] = 19, ["1"] = 5}
--返回单个变量 用中括号填键 来访问
print(a["name"])
print(a["age"])
print(a["1"])
--还可以类型 .成员变量 的形式得到值
print(a.name)
print(a.age)
-- 虽然可以通过,成员变量的形式得到值 但是不能是数字
--print(a.1)
--字典修改
a["name"] = "Sunrise"
print(a["name"])
print(a.name)
--字典新增
a["sex"] = false
print(a["sex"])
print(a.sex)
--字典删除 其实就是置空
a.sex = nil
print(a["sex"])
print(a.sex)print("************字典的遍历***********")
--如果要模拟字典遍历 一定用 pairs
for k,v in pairs(a) doprint(k,v)
end
-- 可以只得键
for k in pairs(a) doprint(k)print(a[k])
endfor _,v in pairs(a) doprint(v)
endprint("**********类和结构体************")print("**********表的公共操作**********")
类
print("**********类和结构体************")--Lua中是默认没有面向对象的 需要我们自己来实现
-- 成员变量 成员函数...
Student = {--年龄age = 1,--性别sex = true,--成长函数Up = function()-- 这样写 这个age 和表中的age没有任何关系 它是一个全局变量--print(age) -- 会输出 nil 而没有输出 1--想要在表内部函数中 调用表本身的属性或者方法--一定要指定是谁的 所以要使用得 表名.属性 或者 表名.方法print(Student.age) -- 输出 1print("成长中")end,--学习函数Learn = function(t)-- 第二种 能够在函数内部调用自己属性或者方法的 方法-- 把自己作为一个参数传进来 在内部访问print(t.sex)print("学习中")end
}--Lua中 .和冒号 的区别
Student.Learn(Student)
--冒号调用方法 会默认把调用者 作为第一个参数传入方法中
Student:Learn()--声明表过后 在表外去声明表有的变量和方法
Student.name = "Sunset"
Student.Speak = function()print("说话")
end
-- 函数的第三种申明方式
function Student:Speak2()--lua中 有一个关键字 self表示 默认传入的第一个参数print(self.name .. "说话2")
end
--C#中要使用类 实例化对象new 静态直接点
--Lua中的类的表现 更新是一个类中有很多 静态变量和函数
print(Student.age)
print(Student.name)
Student.Up()
Student.Speak()
Student:Speak2()
Student.Speak2(Student)
表的公共操作
print("**********表的公共操作**********")
--表中 table提供的一些公共方法的讲解t1 = {{age = 1, name = "123"}, {age = 2, name = "345"}}t2 = {name = "Sunset", sex = true}print("********插入********")
--插入
print(#t1)
table.insert(t1, t2)
print(#t1)
print(t1[1]) -- 打印出的是地址
print(t1[2])
print(t1[3])
print(t1[3].sex)print("********删除********")
--删除指定元素
--remove方法 传表进去 会移除最后一个索引的内容
table.remove(t1)
print(#t1)
print(t1[1].name)
print(t1[2].name)
print(t1[3])--remove方法 传两个参数 第一个参数 是要移除内部的表
--第二个参数 是要移除内容的索引
table.remove(t1, 1)
print(t1[1].name)
print(#t1)print("********排序********")
t2 = {5,3,7,4,1,2}
--传入要排序的表 默认 升序排序
table.sort(t2)
for _,v in pairs(t2) doprint(v)
end
print("********排序自定义升降********")
--传入两个参数 第一个是用于排序的表
--第二个是 排序规则函数
table.sort(t2, function(a,b) -- 降序if a > b thenreturn trueend
end)
for _,v in pairs(t2) doprint(v)
endprint("**********拼接********") -- 了解即可
tb = {"123", "456", "789", "10"}
--连接函数 用于拼接表中元素 返回值 是一个字符串 大部分只能拼接字符串
str = table.concat(tb, ";")
print(str)
11.多Lua脚本执行
print("**************多脚本执行***********")
print("**************全局变量和本地变量***********")
--目前为止我们申明的变量都是 全局变量
a = 1
b = "123"for i=1,2 doc ="Sunset"
end
print(c)--本地(局部)变量的关键字 local
for i=1,2 dolocal d = "Sunset"print("循环中的d"..d)
end
print(d)fun = function()tt = "123123" --所以如果要让它是局部变量就要加 local
end
fun()
print(tt) -- 在没有执行fun() 之前 会返回nil,fun()执行后就变全局变量了-- 只能在自己脚本用的变量
local tt2 = "666"print("**************多脚本执行***********")
--关键字 require("脚本名") require('脚本名')
require("Test") -- 打印 Test测试 456
print(testA) -- 打印 123
print(testLocalA) -- 打印不出 另一个脚本的本地变量print("**************脚本卸载***********")
--如果是require加载执行的脚本 加载一次过后就不会再被执行
require('Test')
--package.loaded["脚本名"]
--返回值是 boolean 意思是 该脚本是否被执行
print(package.loaded["Test"])
--卸载已经执行过的脚本
package.loaded["Test"] = nil;
print(package.loaded["Test"])
--require("Test")--require 执行一个脚本时 可以在脚本最后返回一个外部希望获取的内容
local testLA = require("Test")
print(testLA)print("**************大G表***********")
-- _G 表是一个总表(table)它将我们申明的所有全局变量都存储在其中
for k,v in pairs(_G) doprint(k,v)
end
-- 本地变量 加了local的变量是不会存储到_G表中的
12.特殊用法
print("********特殊用法*********")print("********多变量赋值*********")
a,b,c = 1,2,"123"
print(a)
print(b)
print(c)
--多变量赋值 如果后面的值不够 会自动补空
a,b,c = 1,2
print(a)
print(b)
print(c)
--多变量赋值 如果后面的值多了 会自动省略
a,b,c = 1,2,3,4,5
print(a)
print(b)
print(c)print("********多返回值*********")
function Test()return 10,20,30,40
end
--多返回值时 用几个变量接 就有几个值
--如果少了 就会少接几个 如果多了 就会自动补空
a,b,c = Test()
print(a)
print(b)
print(c)a,b,c,d,e = Test()
print(a)
print(b)
print(c)
print(d)
print(e)print("********and or*********")
-- 逻辑与 逻辑或
-- and or 他们不仅可以连接 boolean 任何东西都可以用来连接
-- 在lua中 只有 nil和false 才认为是假
-- “短路” —— 对于and来说 有假则假 对于or来说 有真则真
-- 所以 他们只需要判断 第一个 是否满足 如果满足就会停止计算了
print(1 and 2) -- 2
print(0 and 1) -- 1
print(nil and 1) -- nul
print(false and 2) -- false
print(true and 3) -- 3print(true or 1) -- true
print(false or 1) -- 1
print(nil or 2) -- 2
print(1 or 2) -- 1--Lua不支持三目运算符 (但是我可以靠and or 模拟出三目运算符来)
x = 3
y = 2
local res = (x > y) and x or y
print(res)
13.协程
print("**********协同程序************")print("**********协程的创建************")
-- 常用方式
--coroutine.create()
fun = function()print(123)
end
co = coroutine.create(fun)
--协程的本质是一个线程对象
print(co) -- 返回 thread 地址
print(type(co)) -- 返回类型 thread 线程--coroutine.wrap()
co2 = coroutine.wrap(fun)
print(co2)
print(type(co2)) -- 返回的 是 function 函数类型print("**********协程的运行************")
--第一种方式 对于的 是通过 create创建的协程
coroutine.resume(co)
--第二种方式
co2()print("**********协程的挂起************")
fun2 = function()local i = 1while true doprint(i)i = i + 1--协程的挂起函数coroutine.yield(i)print(coroutine.status(co3))print(coroutine.running())end
endco3 = coroutine.create(fun2)
--默认第一个返回值 是 协程是否启动成功
--第二个返回值是 yield里面的返回值
isOk, tempI = coroutine.resume(co3)
print(isOk, tempI)
isOk, tempI = coroutine.resume(co3)
print(isOk, tempI)
isOk, tempI = coroutine.resume(co3)
print(isOk, tempI)co4 = coroutine.wrap(fun2)
--co4()
--co4()
--co4()
--这种方式的协程 也可以有返回值 只是没有默认第一个返回值了
print("返回值:"..co4())
print("返回值:"..co4())
print("返回值:"..co4())print("**********协程的状态************")
-- coroutine.status(协程对象)
-- dead 结束
-- suspended 暂停
-- running 进行中
print(coroutine.status(co3))
print(coroutine.status(co))--这个函数可以得到当前正在 运行的协程的线程号
print(coroutine.running())
14.元表
注:知识点较多要配合视频复习
print("************元表**********")
print("************元表概念**********")
--任何表变量都可以作为另一个表变量的元表
--任何表变量都可以有自己的元表(父)
--当我们子表中进行一些特定操作时
--会执行元表中的内容
print("************设置元表**********")
meta = {}
myTable = {}
--设置元表函数
--第一个参数 子表
--第二个参数 元表(父)
setmetatable(myTable, meta)print("************特定操作**********")
print("************特定操作-__tostring**********")
meta2 = {-- 当子表要被当做字符串使用时 会默认调用这个元表中的tostring方法__tostring = function(t) -- tostring 前面有两条下划线return t.nameend
}
myTable2 = {name = "Sunset2"
}
setmetatable(myTable2, meta2)
print(myTable2) --输出 Sunset2print("************特定操作-__call**********")
meta3 = {-- 当子表要被当做字符串使用时 会默认调用这个元表中的tostring方法__tostring = function(t) -- tostring 前面有两条下划线return t.nameend,--当子表被当做一个函数来使用时 会默认调用这个 __call中的内容--当希望传参数时 一定要记住 默认第一个参数 是调用者自己__call = function(a, b)print(a)print(b)print("山有木兮")end
}
myTable3 = {name = "Sunset2"
}
setmetatable(myTable3, meta3)
--把子表当做函数使用 就会调用元表的 __call方法
myTable3(1) -- 输出 Sunset2 1 山有木兮print("************特定操作-运算符重载**********")meta4 = {--相当于运算符重载 当子表使用+运算符时 会调用该方法--运算符+__add = function(t1, t2)return t1.age + t2.ageend, -- 记得打逗号 不然会报错--运算符-__sub = function(t1, t2)return t1.age - t2.ageend,--运算符 *__mul = function(t1, t2)return t1.age * t2.ageend,--运算符 /__div = function(t1, t2)return t1.age / t2.ageend,--运算符 %__mod = function(t1, t2)return t1.age % t2.ageend,--运算符 ^__pow = function(t1, t2)return t1.age ^ t2.ageend,--运算符 ==__eq = function(t1, t2)return t1.age == t2.ageend,--运算符 <__lt = function(t1, t2)return falseend,--运算符 <=__le = function(t1, t2)return tureend,--运算符 ..__concat = function(t1, t2)return "567"end,}
myTable4 = {age = 1}
setmetatable(myTable4, meta4)
myTable5 = {age= 2}
setmetatable(myTable5, meta4)print(myTable4 + myTable5)
print(myTable4 - myTable5)
print(myTable4 * myTable5)
print(myTable4 / myTable5)
print(myTable4 % myTable5)
print(myTable4 ^ myTable5)--如果要用条件运算符 来比较两个对象
--这两个对象的元表一定要一致 才能准确调用方法
print(myTable4 == myTable5)
print(myTable4 < myTable5)
print(myTable4 <= myTable5)
print(myTable4 .. myTable5)print("************特定操作-__index和__newIndex**********")meta6Father = {age = 1
}
meta6Father.__index = meta6Fathermeta6 = {--age = 1--__index = {age = 1}
}
--__index 的赋值 写在外面来初始化
meta6.__index = meta6
--meta6.__index = {age = 1}myTable6 = {}
setmetatable(meta6, meta6Father)
setmetatable(myTable6, meta6)
--得到元表的方法
print(getmetatable(myTable6))-- __index 当子表中 找不到某一个属性时
-- 会到元表中 _index指定的表去找属性
print(myTable6.age)
--rawget 当我们使用它时 会去找自己身上有没有这个变量
--myTable6.age = 6
print(rawget(myTable6, "age"))-- __newIndex 当赋值时,如果赋值一个不存在的索引
-- 那么会把这个值赋值到newindex所指的表中 不会修改自己
meta7 = {}
meta7.__newindex = {}
myTable7 = {}
setmetatable(myTable7, meta7)
myTable7.age = 7
print(myTable7.age)
print(meta7.__newindex.age)
--rawset 该方法 会忽略newindex的设置 只会改自己的变量
rawset(myTable7, "age", 2)
print(myTable7.age)
15.面向对象
封装
print("**********面向对象****************")
print("**********封装****************")
--面向对象 类 其实都是基于 table来实现
--也会元表相关的知识点
Object = {}
Object.id = 1function Object:Test()print(self.id)
end-- 完成 new 对象的操作
-- 冒号 是会自动将调用这个函数的对象 作为第一个参数传入的写法
function Object:new()--self 代表的是 我们默认传入的第一个参数--对象就是变量 返回一个新的变量--返回出去的内容 本质就是表对象local obj = {}--元表知识 __index 当找自己的变量 找不到时 就会去找元素中_index指向的内容self.__index = selfsetmetatable(obj, self)return obj
endlocal myObj = Object:new()
print(myObj)
print(myObj.id)
myObj:Test()
--对空表中 申明一个新的属性id,不会改变元表中的
myObj.id = 2
-- 总结一下:找的到就用自己的,找不到就用别人的,谁调用用谁的self
print(Object.id) -- 还是输出 1
myObj:Test() -- 这里会输出 2print("**********继承****************")print("**********多态***************")
继承
print("**********面向对象****************")
print("**********封装****************")
--面向对象 类 其实都是基于 table来实现
--也会元表相关的知识点
Object = {}
Object.id = 1function Object:Test()print(self.id)
end-- 完成 new 对象的操作
-- 冒号 是会自动将调用这个函数的对象 作为第一个参数传入的写法
function Object:new()--self 代表的是 我们默认传入的第一个参数--对象就是变量 返回一个新的变量--返回出去的内容 本质就是表对象local obj = {}--元表知识 __index 当找自己的变量 找不到时 就会去找元素中_index指向的内容self.__index = selfsetmetatable(obj, self)return obj
endlocal myObj = Object:new()
print(myObj)
print(myObj.id)
myObj:Test()
--对空表中 申明一个新的属性id,不会改变元表中的
myObj.id = 2
-- 总结一下:找的到就用自己的,找不到就用别人的,谁调用用谁的self
print(Object.id) -- 还是输出 1
myObj:Test() -- 这里会输出 2print("**********继承****************")
--C# class 类名 : 继承类
--写一个用于继承的方法
function Object:subClass(className)-- _G知识点 是总表 所有声明的全局标量 都以键值对的形式存在其中_G[className] = {}--写相关继承的规则--要用到元表local obj = _G[className]self.__index = selfsetmetatable(obj, self)
endObject:subClass("Person")
--print(Person)
--print(Person.id)local p1 = Person:new()
print(p1.id) -- 还是打印的 Object 的 id 1
p1.id = 100
print(p1.id)
p1:Test()Object:subClass("Monster")
local m1 = Monster:new()
print(m1.id)
m1.id = 200
print(m1.id)
m1:Test()-- 补充 _G 的一些其他用法
--print(_G) --输出 table 加 地址 _G本质也是一张表
--_G["a"] = 1
--_G.b = "123"
--print(a) -- 1
--print(b) -- 123print("**********多态***************")
多态
print("**********面向对象****************")
print("**********封装****************")
--面向对象 类 其实都是基于 table来实现
--也会元表相关的知识点
Object = {}
Object.id = 1function Object:Test()print(self.id)
end-- 完成 new 对象的操作
-- 冒号 是会自动将调用这个函数的对象 作为第一个参数传入的写法
function Object:new()--self 代表的是 我们默认传入的第一个参数--对象就是变量 返回一个新的变量--返回出去的内容 本质就是表对象local obj = {}--元表知识 __index 当找自己的变量 找不到时 就会去找元素中_index指向的内容self.__index = selfsetmetatable(obj, self)return obj
endlocal myObj = Object:new()
print(myObj)
print(myObj.id)
myObj:Test()
--对空表中 申明一个新的属性id,不会改变元表中的
myObj.id = 2
-- 总结一下:找的到就用自己的,找不到就用别人的,谁调用用谁的self
print(Object.id) -- 还是输出 1
myObj:Test() -- 这里会输出 2print("**********继承****************")
--C# class 类名 : 继承类
--写一个用于继承的方法
function Object:subClass(className)-- _G知识点 是总表 所有声明的全局标量 都以键值对的形式存在其中_G[className] = {}--写相关继承的规则--要用到元表local obj = _G[className]-- 子类 定义个base属性 base属性代表父类obj.base = selfself.__index = selfsetmetatable(obj, self)
endObject:subClass("Person")
--print(Person)
--print(Person.id)local p1 = Person:new()
print(p1.id) -- 还是打印的 Object 的 id 1
p1.id = 100
print(p1.id)
p1:Test()Object:subClass("Monster")
local m1 = Monster:new()
print(m1.id)
m1.id = 200
print(m1.id)
m1:Test()-- 补充 _G 的一些其他用法
--print(_G) --输出 table 加 地址 _G本质也是一张表
--_G["a"] = 1
--_G.b = "123"
--print(a) -- 1
--print(b) -- 123print("**********多态***************")
--多态:相同行为 不同表现 就是多态
-- 相同方法 不同执行逻辑 就是多态
Object:subClass("GameObject")
GameObject.posX = 0
GameObject.posY = 0
function GameObject:Move()self.posX = self.posX + 1self.posY = self.posY + 1print(self.posX)print(self.posY)
endGameObject:subClass("Player")
-- 这样就已经实现了多态的 相同方法 不同表现 但是问题来了 我们如何保留父类的逻辑
function Player:Move()--base 指定是 GameObject 表(类)--这种方式调用 相当于是把基类表 作为第一个参数传入方法中--导致它们都在共用 GameObject中的Move方法数据--self.base:Move() --通过 记录的base 来保留父类的方法逻辑--我们如果要执行父类逻辑 我们不要直接使用冒号调用--要通过 . 来调用 然后自己传入第一个参数self.base.Move(self)
endlocal p1 = Player:new()
p1:Move()
p1:Move()-- but 目前这种写法 有bug 不同对象使用的成员变量 是相同的成员变量
-- 并没有使用它们自己的
local p2 = Player:new()
p2:Move()
总结
--面向对象实现
--万物之父 所有对象的基类 Object-- 封装
Object = {}--实例化方法
function Object:new()local obj = {}--给空对象设置元表 以及 __indexself.__index = selfsetmetatable(obj, self)return obj
end--继承
function Object:subClass(className)--根据名字生成一张表 就是一个类_G[className] = {}local obj = _G[className]--设置自己的“父类”obj.base = self--给子类设置元表 以及 __indexself.__index = selfsetmetatable(obj, self)
end-- 多态 一般是在使用中的一种表现--测试
--申明一个新的类
Object:subClass("GameObject")
--成员变量
GameObject.posX = 0
GameObject.posY = 0
--成员方法
function GameObject:Move()self.posX = self.posX + 1self.posY = self.posY + 1
end--实例化对象使用
local obj = GameObject:new()
print(obj.posX)
obj:Move()
print(obj.posX)local obj2 = GameObject:new()
print(obj2.posX)
obj2:Move()
print(obj2.posX)--申明一个新的类 Player 继承 GameObject
GameObject:subClass("Player")
--多态 重写 GameObject的Move方法
function Player:Move()--base调用父类方法 用 . 自己传第一个参数self.base.Move(self)
endprint("*******")
--声明实例化 Player对象
local p1 = Player:new()
print(p1.posX)
p1:Move()
print(p1.posX)local p2 = Player:new()
print(p2.posX)
p2:Move()
print(p2.posX)
16.自带库
print("************自带库*********")
--string
--table
print("************数字运算*********")
--系统时间
print(os.time())
--自己传入参数 得到时间
print(os.time({year = 2014, month = 8, day = 14}))-- os.date("*t")
local nowTime = os.date("*t")
for k,v in pairs(nowTime) doprint(k,v)
end
print(nowTime.day)
print(nowTime.hour)print("************数学运算*********")
--math
--绝对值
print(math.abs(-11))
--弧度转角度
print(math.deg(math.pi))
--三角函数 传的是弧度
print(math.cos(math.pi)) --其它的sin...都是这样--向下向上取整
print(math.floor(2.6))
print(math.ceil(5.1))--最大最小值
print(math.max(1,2))
print(math.min(4,5))--小数分离 分成整数部分和小数部分
print(math.modf(1.2)) -- 1 0.2-- 幂运算 还有^ 也是
print(math.pow(2, 5))--随机数
--先设置随机数种子
math.randomseed(os.time())
print(math.random(100))
print(math.random(100))--开方 就是开根号
print(math.sqrt(9))print("************路径*********")
--lua脚本加载路径
print(package.path)
package.path = package.path .. ";C:\\"
print(package.path)
17.Lua垃圾回收
相关文章:

热更新解决方案2 —— Lua语法相关知识点
概述 开发环境搭建 Lua语法 1.第一个Lua程序 2.变量 print("******变量*******"); --lua当中的简单变量类型 -- nil number string boolean -- lua 中所有的变量声明 都不需要声明变量类型 它会自动的判断类型 -- 类似C# 中的var --lua中的一个变量 可以随便赋值 ——…...
【c++ arx选项板】
static void xlArx_gmenu(void) {if (!g_pPaletteSetEx){g_pPaletteSetEx=CTunnelSectionPaletteSetEx::Instance(...
新时代下吉林省城乡流动人才就业问题及路径探析
摘要:新时代背景下,中国经济快速发展,城乡融合发展成为缩小城乡差距,推动共同富裕的重要方式。吉林省作为东北老工业基地,传统产业竞争优势减弱,城乡流动人才就业规模增加,并呈现“农村-城市”的…...

Go 1.19.4 命令调用、日志、包管理、反射-Day 17
1. 系统命令调用 所谓的命令调用,就是通过os,找到系统中编译好的可执行文件,然后加载到内存中,变成进程。 1.1 exec.LookPath(寻找命令) 作用: exec.LookPath 函数用于在系统的环境变量中搜索可…...

Unity 2d UI 实时跟随场景3d物体
2d UI 实时跟随场景3d物体位置,显示 3d 物体头顶信息,看起来像是场景中的3dUI,实质是2d UIusing System.Collections; using System.Collections.Generic; using UnityEngine; using DG.Tweening; using UnityEngine.UI; /// <summary>…...

全方面熟悉Maven项目管理工具(二)坐标、pom.xml文件的解读!
1. 坐标(核心概念) 1.1 数学中的坐标 使用 x、y、z 三个向量作为空间的坐标系,可以在空间中唯一的定位到一个点 1.2 Maven 中的坐标 1.2.1 向量说明: 使用三个向量在 Maven的仓库 中唯一的定位到一个 jar 包 groupId…...
php常用设计模式之单例模式
设计模式是我们日常开发中最常用的编程模式之一,也是面试中最高频的考点之一。通过合理运用设计模式,可以使代码结构更加清晰、易于维护。通过这篇文章 我也讲一下设计模式中的单例模式,了解下它的原理和适用场景。 单例模式 单例模式&…...
一文搞懂Android主题和样式
1. 概念与作用 1.1 定义与组成 Android Theme是用于定义应用程序或其部分的视觉和界面风格的一种资源。主题在Android中扮演着重要的角色,它们允许开发者统一和自定义应用的外观和感觉。一个主题定义了一组属性集合,这些属性可以是颜色、字体、控件样式…...

360与重庆科技大学战略携手,为数字中国建设输送实战人才
近日,360数字安全集团与重庆科技大学正式签订了战略合作协议,双方将围绕创新人才培养、科研技术攻关、专业实验室共建、车联网安全以及社会服务等多个维度展开深度合作,共同打造数字安全人才培养新高地,为数字重庆的建设与发展注入…...

基于异常合成的图像异常检测方法
基于异常合成的图像异常检测方法 基于异常合成思路实现图像异常检测的方法,它们的核心思路是: 试图通过合成异常样本穷尽所有可能出现的异常类型,从而将无监督的异常检测(one class classification)建模为一个全监督…...
机器学习方向在算法优化上有哪些创新点?
以下是机器学习算法优化方面的一些创新点: 一、优化算法自身的改进 随机梯度下降(SGD)的变体 Adagrad 传统的随机梯度下降算法使用固定的学习率,而Adagrad根据每个参数的历史梯度信息自适应地调整学习率。对于稀疏数据,它可以为不同的参数分配不同的学习率,使得频繁出现…...

基于yolov8的道路交通事故检测系统python源码+onnx模型+评估指标曲线+精美GUI界面
【算法介绍】 基于YOLOV8的道路交通事故检测系统是一种先进的智能交通监控解决方案,它利用YOLOV8这一前沿的目标检测算法,实现对交通事故的高效、实时检测。 该系统结合了自定义的道路交通事故数据集,对YOLOV8模型进行了针对性的训练与优化…...
HttpUtils 详解
一、详解 1.1 介绍 现如今的 Web 项目,由服务端向外发起网络请求的场景,基本上随处可见! 传统情况下,在服务端代码里访问 http 服务时,一般会使用 JDK 的 HttpURLConnection 或者 Apache 的 HttpClient,不…...

云计算第四阶段: cloud二周目 07-08
cloud 07 一、k8s服务管理 创建服务 # 资源清单文件 [rootmaster ~]# kubectl create service clusterip websvc --tcp80:80 --dry-runclient -o yaml [rootmaster ~]# vim websvc.yaml --- kind: Service apiVersion: v1 metadata:name: websvc spec:type: ClusterIPselector…...
智能合约开发工具Remix
不久前,我在B站、视频号和 YouTube 都陆续发布了新的一套免费视频课程《智能合约开发工具Remix》,总共分为了 9 个小节的视频,以下分别是这 9 个小节在 B 站的视频链接,喜欢直接看视频的伙伴可以去 B 站观看: 概况文件…...

YYF桌面 1.2 | 个性化桌面体验,清爽美观。
YYF桌面是一款经过定制的安卓桌面启动器,此版本基于1.2版本进行了一系列个性化修改。主界面快捷图标进行了美化处理,并采用了清爽半透明的图标背景。取消了底部快捷键,并重新制作了“全部应用”按钮,保留了动态效果。修改了右上角…...

【人工智能/计算机工程/大数据】第五届人工智能与计算工程国际学术会议(ICAICE 2024,2024年11月8-10日)
The 5th International Conference on Artificial Intelligence and Computer Engineering 第五届人工智能与计算工程国际学术会议(ICAICE 2024) 会议官网:www.event-icaice.org The 5th International Conference on Artificial Intellige…...
uni-app录音功能
纯纯干货,cv即用 <template><!-- 录音页面 --><view class"page"><view class"tape_box"><view class"upload_box1"><view class"upload_top"><view class"upload_img_title…...

C语言【调试】(个人笔记版)
调试 前言一、Bug二、调试工具1.DeBug2.Release 三、调试快捷键1、断点 四、调试时查看程序的当前信息1、查看临时变量2、查看内存3、查看调用堆栈、汇编、寄存器 总结 前言 这篇文章大都是我的个人笔记: 调试在日常程序设计中是很重要的。调试说白了就是为了解决代…...

连锁收银系统
商淘云连锁管理系统助力连锁企业实现“人货账”全方位数字化管理,它依托连锁品牌进销存管理实现门店订货、线下收银、线上商城、会员营销等一体化管理。 门店订货补货支持连锁直营、加盟 不同门店不同进货价、不同门店不同商品、不同门店在线或者账期支付、门店PC或…...
[2025CVPR]DeepVideo-R1:基于难度感知回归GRPO的视频强化微调框架详解
突破视频大语言模型推理瓶颈,在多个视频基准上实现SOTA性能 一、核心问题与创新亮点 1.1 GRPO在视频任务中的两大挑战 安全措施依赖问题 GRPO使用min和clip函数限制策略更新幅度,导致: 梯度抑制:当新旧策略差异过大时梯度消失收敛困难:策略无法充分优化# 传统GRPO的梯…...

CTF show Web 红包题第六弹
提示 1.不是SQL注入 2.需要找关键源码 思路 进入页面发现是一个登录框,很难让人不联想到SQL注入,但提示都说了不是SQL注入,所以就不往这方面想了 先查看一下网页源码,发现一段JavaScript代码,有一个关键类ctfs…...
PHP和Node.js哪个更爽?
先说结论,rust完胜。 php:laravel,swoole,webman,最开始在苏宁的时候写了几年php,当时觉得php真的是世界上最好的语言,因为当初活在舒适圈里,不愿意跳出来,就好比当初活在…...

【入坑系列】TiDB 强制索引在不同库下不生效问题
文章目录 背景SQL 优化情况线上SQL运行情况分析怀疑1:执行计划绑定问题?尝试:SHOW WARNINGS 查看警告探索 TiDB 的 USE_INDEX 写法Hint 不生效问题排查解决参考背景 项目中使用 TiDB 数据库,并对 SQL 进行优化了,添加了强制索引。 UAT 环境已经生效,但 PROD 环境强制索…...
质量体系的重要
质量体系是为确保产品、服务或过程质量满足规定要求,由相互关联的要素构成的有机整体。其核心内容可归纳为以下五个方面: 🏛️ 一、组织架构与职责 质量体系明确组织内各部门、岗位的职责与权限,形成层级清晰的管理网络…...
[Java恶补day16] 238.除自身以外数组的乘积
给你一个整数数组 nums,返回 数组 answer ,其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积 。 题目数据 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内。 请 不要使用除法,且在 O(n) 时间复杂度…...
JS设计模式(4):观察者模式
JS设计模式(4):观察者模式 一、引入 在开发中,我们经常会遇到这样的场景:一个对象的状态变化需要自动通知其他对象,比如: 电商平台中,商品库存变化时需要通知所有订阅该商品的用户;新闻网站中࿰…...

【从零学习JVM|第三篇】类的生命周期(高频面试题)
前言: 在Java编程中,类的生命周期是指类从被加载到内存中开始,到被卸载出内存为止的整个过程。了解类的生命周期对于理解Java程序的运行机制以及性能优化非常重要。本文会深入探寻类的生命周期,让读者对此有深刻印象。 目录 …...

2025年渗透测试面试题总结-腾讯[实习]科恩实验室-安全工程师(题目+回答)
安全领域各种资源,学习文档,以及工具分享、前沿信息分享、POC、EXP分享。不定期分享各种好玩的项目及好用的工具,欢迎关注。 目录 腾讯[实习]科恩实验室-安全工程师 一、网络与协议 1. TCP三次握手 2. SYN扫描原理 3. HTTPS证书机制 二…...

Chrome 浏览器前端与客户端双向通信实战
Chrome 前端(即页面 JS / Web UI)与客户端(C 后端)的交互机制,是 Chromium 架构中非常核心的一环。下面我将按常见场景,从通道、流程、技术栈几个角度做一套完整的分析,特别适合你这种在分析和改…...