热更新解决方案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)  -- ture

print(true or false)  -- true
print(false or false) -- false

print(not true) -- false

print("********短路测试*********")
print(false and print("123"))  -- 输出 false
print(true and print("123"))  -- 输出: 123 nil

print("*******位运算符********")
-- & | lua中不支持位运算符 需要我们自己实现

print("*******三目运算符********")
-- lua中也不支持三目运算符

5.条件分支语句

print("***********条件分支语句************")
a = 9
-- if 条件 then...end
--单分支
if a > 5 then
	print("124")
end

--双分支
--if 条件 then...else...end
if a < 5 then
	print("123")
else
	print("321")
end

--多分支
--if 条件 then...elseif 条件 then...elseif 条件 then...else...end
if a < 5 then
	print("123")
--lua中 elseif 一定是连着写的 否则会报错
elseif a == 6 then
	print("6")
elseif a == 7 then
	print("7")
elseif a == 8 then
	print("8")
elseif a == 9 then
	print("9")
else
	print("other")
end

-- 组合条件的使用
if a >= 3 and a <= 9 then
	print("3到9之间")
end


-- Lua中没有switch 需要的话可以自己实现

6.循环

7.函数

print("********函数*******")
--function 函数名()
--end

--a = function()
--end

print("********无参数无返回值*******")
-- 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)
end

F6()  -- 输出 il


print("********变长参数*******")
function F7(...)
	--变长参数使用 用一个表存起来 再用
	arg = {...}
	for i = 1,#arg do
		print(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
end

f9 = F8()
f9()

--Lua 中闭包的体现
function F9(x)
	--改变传入参数的生命周期
	return function(y)
		return x + y
	end
end

f10 = 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)  -- 输出 2

print("*********数组的遍历***********")
for i = 1,#a do
	print(a[i])
end

print("*********二维数组***********")
--注意 其实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 do
	b = a[i]
	for j = 1,#b do
		print(b[j])
	end
end

print("*********自定义索引***********")
-- 不建议自定义索引
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) do
	print(k,v)
end
-- 可以只得键
for k in pairs(a) do
	print(k)
	print(a[k])
end

for _,v in pairs(a) do
	print(v)
end


print("**********类和结构体************")

print("**********表的公共操作**********")

print("**********类和结构体************")

--Lua中是默认没有面向对象的 需要我们自己来实现
-- 成员变量 成员函数...
Student = {
	--年龄
	age = 1,
	--性别
	sex = true,
	--成长函数
	Up = function()
		-- 这样写 这个age 和表中的age没有任何关系 它是一个全局变量
		--print(age)  -- 会输出 nil    而没有输出 1

		--想要在表内部函数中 调用表本身的属性或者方法
		--一定要指定是谁的 所以要使用得 表名.属性  或者  表名.方法
		print(Student.age)  -- 输出 1
		print("成长中")
	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) do
	print(v)
end
print("********排序自定义升降********")
--传入两个参数 第一个是用于排序的表
--第二个是 排序规则函数   
table.sort(t2, function(a,b)  -- 降序
	if a > b then
		return true
	end
end)
for _,v in pairs(t2) do
	print(v)
end

print("**********拼接********")  -- 了解即可
tb = {"123", "456", "789", "10"}
--连接函数 用于拼接表中元素 返回值 是一个字符串 大部分只能拼接字符串
str = table.concat(tb, ";")
print(str)

11.多Lua脚本执行

print("**************多脚本执行***********")
print("**************全局变量和本地变量***********")
--目前为止我们申明的变量都是 全局变量
a = 1
b = "123"

for i=1,2 do
	c ="Sunset"
end
print(c)

--本地(局部)变量的关键字 local
for i=1,2 do
	local 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) do
	print(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)  -- 3

print(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 = 1
	while true do
		print(i)
		i = i + 1
		--协程的挂起函数
		coroutine.yield(i)
		print(coroutine.status(co3))
		print(coroutine.running())
	end
end

co3 = 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.name
	end
}
myTable2 = {
	name = "Sunset2"
}
setmetatable(myTable2, meta2)
print(myTable2)  --输出 Sunset2

print("************特定操作-__call**********")
meta3 = {
	-- 当子表要被当做字符串使用时 会默认调用这个元表中的tostring方法
	__tostring = function(t)  -- tostring 前面有两条下划线
		return t.name
	end,
	--当子表被当做一个函数来使用时 会默认调用这个 __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.age
	end,   -- 记得打逗号 不然会报错
	--运算符-
	__sub = function(t1, t2)
		return t1.age - t2.age
	end,
	--运算符 *
	__mul = function(t1, t2)
		return t1.age * t2.age
	end,
	--运算符 /
	__div = function(t1, t2)
		return t1.age / t2.age
	end,
	--运算符 %
	__mod = function(t1, t2)
		return t1.age % t2.age
	end,
	--运算符 ^
	__pow = function(t1, t2)
		return t1.age ^ t2.age
	end,
	--运算符 ==
	__eq = function(t1, t2)
		return t1.age == t2.age
	end,
	--运算符 <
	__lt = function(t1, t2)
		return false
	end,
	--运算符 <=
	__le = function(t1, t2)
		return ture
	end,
	--运算符 ..
	__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 = meta6Father

meta6 = {
	--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 = 1

function Object:Test()
	print(self.id)
end

-- 完成 new 对象的操作
-- 冒号 是会自动将调用这个函数的对象 作为第一个参数传入的写法
function Object:new()
	--self 代表的是 我们默认传入的第一个参数
	--对象就是变量 返回一个新的变量
	--返回出去的内容 本质就是表对象
	local obj = {}
	--元表知识 __index 当找自己的变量 找不到时 就会去找元素中_index指向的内容
	self.__index = self
	setmetatable(obj, self)
	return obj
end

local myObj = Object:new()
print(myObj)
print(myObj.id)
myObj:Test()
--对空表中 申明一个新的属性id,不会改变元表中的
myObj.id = 2
-- 总结一下:找的到就用自己的,找不到就用别人的,谁调用用谁的self
print(Object.id)  -- 还是输出 1
myObj:Test()  -- 这里会输出 2


print("**********继承****************")

print("**********多态***************")

继承

print("**********面向对象****************")
print("**********封装****************")
--面向对象 类 其实都是基于 table来实现
--也会元表相关的知识点
Object = {}
Object.id = 1

function Object:Test()
	print(self.id)
end

-- 完成 new 对象的操作
-- 冒号 是会自动将调用这个函数的对象 作为第一个参数传入的写法
function Object:new()
	--self 代表的是 我们默认传入的第一个参数
	--对象就是变量 返回一个新的变量
	--返回出去的内容 本质就是表对象
	local obj = {}
	--元表知识 __index 当找自己的变量 找不到时 就会去找元素中_index指向的内容
	self.__index = self
	setmetatable(obj, self)
	return obj
end

local myObj = Object:new()
print(myObj)
print(myObj.id)
myObj:Test()
--对空表中 申明一个新的属性id,不会改变元表中的
myObj.id = 2
-- 总结一下:找的到就用自己的,找不到就用别人的,谁调用用谁的self
print(Object.id)  -- 还是输出 1
myObj:Test()  -- 这里会输出 2


print("**********继承****************")
--C# class 类名 : 继承类
--写一个用于继承的方法
function Object:subClass(className)
	-- _G知识点 是总表 所有声明的全局标量 都以键值对的形式存在其中
	_G[className] = {}
	--写相关继承的规则
	--要用到元表
	local obj = _G[className]
	self.__index = self
	setmetatable(obj, self)
end

Object: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)  -- 123



print("**********多态***************")

多态

print("**********面向对象****************")
print("**********封装****************")
--面向对象 类 其实都是基于 table来实现
--也会元表相关的知识点
Object = {}
Object.id = 1

function Object:Test()
	print(self.id)
end

-- 完成 new 对象的操作
-- 冒号 是会自动将调用这个函数的对象 作为第一个参数传入的写法
function Object:new()
	--self 代表的是 我们默认传入的第一个参数
	--对象就是变量 返回一个新的变量
	--返回出去的内容 本质就是表对象
	local obj = {}
	--元表知识 __index 当找自己的变量 找不到时 就会去找元素中_index指向的内容
	self.__index = self
	setmetatable(obj, self)
	return obj
end

local myObj = Object:new()
print(myObj)
print(myObj.id)
myObj:Test()
--对空表中 申明一个新的属性id,不会改变元表中的
myObj.id = 2
-- 总结一下:找的到就用自己的,找不到就用别人的,谁调用用谁的self
print(Object.id)  -- 还是输出 1
myObj:Test()  -- 这里会输出 2


print("**********继承****************")
--C# class 类名 : 继承类
--写一个用于继承的方法
function Object:subClass(className)
	-- _G知识点 是总表 所有声明的全局标量 都以键值对的形式存在其中
	_G[className] = {}
	--写相关继承的规则
	--要用到元表
	local obj = _G[className]
	-- 子类 定义个base属性 base属性代表父类
	obj.base = self
	self.__index = self
	setmetatable(obj, self)
end

Object: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)  -- 123



print("**********多态***************")
--多态:相同行为 不同表现 就是多态
-- 相同方法 不同执行逻辑 就是多态
Object:subClass("GameObject")
GameObject.posX = 0
GameObject.posY = 0
function GameObject:Move()
	self.posX = self.posX + 1
	self.posY = self.posY + 1
	print(self.posX)
	print(self.posY)
end

GameObject:subClass("Player")
-- 这样就已经实现了多态的 相同方法 不同表现  但是问题来了 我们如何保留父类的逻辑
function Player:Move()
	--base 指定是 GameObject 表(类)
	--这种方式调用 相当于是把基类表 作为第一个参数传入方法中
	--导致它们都在共用 GameObject中的Move方法数据
	--self.base:Move()  --通过 记录的base 来保留父类的方法逻辑
	--我们如果要执行父类逻辑 我们不要直接使用冒号调用
	--要通过 . 来调用 然后自己传入第一个参数
	self.base.Move(self)
end

local p1 = Player:new()
p1:Move()
p1:Move()

-- but 目前这种写法 有bug 不同对象使用的成员变量  是相同的成员变量
-- 并没有使用它们自己的
local p2 = Player:new()
p2:Move()



总结

--面向对象实现
--万物之父 所有对象的基类 Object

-- 封装
Object = {}

--实例化方法  
function Object:new()
	local obj = {}
	--给空对象设置元表 以及 __index
	self.__index = self
	setmetatable(obj, self)
	return obj
end

--继承
function Object:subClass(className)
	--根据名字生成一张表 就是一个类
	_G[className] = {}
	local obj = _G[className]
	--设置自己的“父类”
	obj.base = self
	--给子类设置元表 以及 __index
	self.__index = self
	setmetatable(obj, self)
end

-- 多态 一般是在使用中的一种表现


--测试
--申明一个新的类
Object:subClass("GameObject")
--成员变量
GameObject.posX = 0
GameObject.posY = 0
--成员方法
function GameObject:Move()
	self.posX = self.posX + 1
	self.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)
end

print("*******")
--声明实例化 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) do
	print(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垃圾回收

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Product1M 深度理解 PPT

系列论文研读目录 文章目录 系列论文研读目录 模态内检索&#xff1a;是指在同一模态&#xff08;例如&#xff0c;图像、文本或音频&#xff09;中进行的检索任务。它通常涉及在同一类型的数据中查找相关项。比如下面图像只能查询图像&#xff0c;文本只能查询文本&#xff0c…

modbus tcp wireshark抓包

Modbus TCP报文详解与wireshark抓包分析_mbap-CSDN博客 关于wireshark无法分析出modbusTCP报文的事情_wireshark 协议一列怎么没有modbus tcp-CSDN博客 使用Wireshark过滤Modbus功能码 - 技象科技 连接建立以后才能显示Modbus TCP报文 modbus.func_code 未建立连接时&…

D36【python 接口自动化学习】- python基础之函数

day36 函数的定义 学习日期&#xff1a;20241013 学习目标&#xff1a;输入输出与文件操作&#xfe63;-49 函数定义&#xff1a;如何优雅地反复引用同一段代码&#xff1f; 学习笔记&#xff1a; 函数的用途 定义函数 调用函数 # 定义函数 def foo():print(foo)print(foo …

胤娲科技:AI短视频——创意无界,即梦启航

在这个快节奏的时代&#xff0c;你是否曾梦想过用几秒钟的短视频&#xff0c;捕捉生活中的每一个精彩瞬间&#xff1f;是否曾幻想过&#xff0c;即使没有专业的摄影和剪辑技能&#xff0c;也能创作出令人惊艳的作品&#xff1f; 现在&#xff0c;这一切都不再是遥不可及的梦想。…

一区鱼鹰优化算法+深度学习+注意力机制!OOA-TCN-LSTM-Attention多变量时间序列预测

一区鱼鹰优化算法深度学习注意力机制&#xff01;OOA-TCN-LSTM-Attention多变量时间序列预测 目录 一区鱼鹰优化算法深度学习注意力机制&#xff01;OOA-TCN-LSTM-Attention多变量时间序列预测预测效果基本介绍程序设计参考资料 预测效果 基本介绍 1.基于OOA-TCN-LSTM-Attenti…

Mysql(八) --- 视图

文章目录 前言1.什么是视图&#xff1f;2.创建视图3. 使用视图4. 修改数据4.1.注意事项 5. 删除视图6.视图的优点 前言 前面我们学习了索引&#xff0c;这次我们来学习视图 1.什么是视图&#xff1f; 视图是一个虚拟的表&#xff0c;它是基于一个或多个基本表或其他视图的查询…

Docker 入门篇

&#x1f3dd;️ 博主介绍 大家好&#xff0c;我是一个搬砖的农民工&#xff0c;很高兴认识大家 &#x1f60a; ~ &#x1f468;‍&#x1f393; 个人介绍&#xff1a;本人是一名后端Java开发工程师&#xff0c;坐标北京 ~ &#x1f389; 感谢关注 &#x1f4d6; 一起学习 &…

05 django管理系统 - 部门管理 - 修改部门

04我们已经实现了新增部门的功能&#xff0c;下面开始修改部门模块的实现。 按道理来说&#xff0c;应该是做成弹框样式的&#xff0c;通过ajax悄咪咪的发数据&#xff0c;然后更新前端数据&#xff0c;但是考虑到实际情况&#xff0c;先用页面跳转的方式实现&#xff0c;后面…

106页PPT企业管控模式方案:战略、产业与职能管理体系核心规划

企业集团管控模式的设计方案是一个复杂而系统的过程&#xff0c;其核心规划涉及到战略、产业与职能管理体系。以下是对这三个方面的详细规划&#xff1a; 一、战略规划 明确集团战略目标&#xff1a;集团应根据市场环境和自身优势&#xff0c;明确战略发展方向和目标&#xf…

Tailwind Starter Kit 一款极简的前端快速启动模板

Tailwind Starter Kit 是基于TailwindCSS实现的一款开源的、使用简单的极简模板扩展。会用Tailwincss就可以快速入手使用。Tailwind Starter Kit 是免费开源的。它不会在原始的TailwindCSS框架中更改或添加任何CSS。它具有多个HTML元素&#xff0c;并附带了ReactJS、Vue和Angul…

JavaScript 网页设计案例:使用 Canvas 实现趣味打气球小游戏

JavaScript 网页设计案例&#xff1a;使用 Canvas 实现趣味打气球小游戏 在网页设计中&#xff0c;交互性和趣味性是吸引用户的重要因素。借助 JavaScript 和 HTML5 的 canvas 元素&#xff0c;我们可以轻松实现各种动画效果&#xff0c;今天将带你打造一个有趣的 打气球小游戏…

Metasploit渗透测试之攻击终端设备和绕过安全软件

概述 在之前&#xff0c;重点讨论了针对服务器端的利用。但在当下&#xff0c;最成功的攻击都是针对终端的&#xff1b;原因是&#xff0c;随着大部分安全预算和关注都转向面向互联网的服务器和服务&#xff0c;越来越难找到可利用的服务&#xff0c;或者至少是那些还没有被破…

大规模多传感器滑坡检测数据集,利用landsat,哨兵2,planet,无人机图像等多种传感器采集数据共2w余副图像,mask准确标注滑坡位置

大规模多传感器滑坡检测数据集&#xff0c;利用landsat&#xff0c;哨兵2&#xff0c;planet&#xff0c;无人机图像等多种传感器采集数据共2w余副图像&#xff0c;mask准确标注滑坡位置 大规模多传感器滑坡检测数据集介绍 数据集概述 名称&#xff1a;大规模多传感器滑坡检测…

云计算第四阶段-----CLOUND二周目 04-06

cloud 04 今日目标&#xff1a; 一、Pod 生命周期 图解&#xff1a; [rootmaster ~]# vim web1.yaml --- kind: Pod apiVersion: v1 metadata:name: web1 spec:initContainers: # 定义初始化任务- name: task1 # 如果初始化任务失败&#…

计算机网络:数据链路层 —— 共享式以太网

文章目录 共享式以太网CSMA/CD 协议CSMA/CD 协议 的基本原理 共享式以太网的争用期共享式以太网的最小帧长共享式以太网的最大帧长共享式以太网的退避算法截断二进制指数退避算法 共享二进制以太网的信道利用率使用集线器的共享式以太网10BASE-T 共享式以太网 共享式以太网是当…

安宝特方案 | AR技术在轨交行业的应用优势

随着轨道交通行业不断向智能化和数字化转型&#xff0c;传统巡检方式的局限性日益凸显。而安宝特AR眼镜以其独特的佩戴方式和轻便设计&#xff0c;为轨道交通巡检领域注入了创新活力&#xff0c;提供了全新的解决方案。 01 多样化佩戴方法&#xff0c;完美适应户外环境 安宝特…

鸿蒙NEXT开发-知乎评论小案例(基于最新api12稳定版)

注意&#xff1a;博主有个鸿蒙专栏&#xff0c;里面从上到下有关于鸿蒙next的教学文档&#xff0c;大家感兴趣可以学习下 如果大家觉得博主文章写的好的话&#xff0c;可以点下关注&#xff0c;博主会一直更新鸿蒙next相关知识 专栏地址: https://blog.csdn.net/qq_56760790/…

盘点超好用的 Windows 录屏软件,轻松记录屏幕精彩

在当今数字化信息高速流转的时代&#xff0c;屏幕录制已经成为我们日常工作、学习和娱乐中不可或缺的一项技能。如果你是微软电脑&#xff0c;正好我今天想要介绍的就是windows怎么录屏相关工具的操作&#xff0c;感兴趣就继续往下看吧。 1.FOXIT录屏大师 链接直达&#xff1…

鸿蒙开发实战项目【硅谷租房】--- 项目介绍

目录 一、简述 二、项目资料 2.1 UI设计稿 2.2 服务器 2.3 Apifox接口JSON文件 使用 Apifox 测试接口 一、简述 这是一个基于 鸿蒙 API12 开发的移动端租房 App&#xff0c;用户可以使用该应用搜索租房列表、查看房屋详情、预约租房等。 该项目的tabbar包含五部分&…

Ubuntu系统下的用户管理

Ubuntu系统下的用户管理 一、ubuntu介绍1.1 ubuntu简介1.2 主要特点 二、创建新用户2.1 查看当前Ubuntu版本2.2 创建新用户2.3 修改密码2.4 查看用户id 三、新建用户组3.1 新建用户组3.2 查询用户组3.3 加入某个用户组 四、赋予sudo权限4.1 将用户添加到 sudo 组4.2 查看admin用…