Lua语法笔记分享

本文有很多和C#对比的例子,所以需要一定C#基础语法。也可以在这个链接查看,有目录方便一点 https://www.notion.so/Lua-f6d39800f8ec4072b5a048fbd42c4a6f

目录


第一章 Lua基本语法

1.1 分号

  • Lua的分号可以省略。

1.2 注释

  • 单行注释
--单行注释
  • 多行注释
--[[
多行
注释
]]
--[[
第二种
多行
注释
]]--
--[[
第三种
多行
注释
--]]

1.3 print打印

print("Hello,world!!")

第2章 简单变量类型

  • Lua中的简单变量类型 nil number string boolean
  • Lua中所以的变量声明,都不需要声明变量类型,他会自动的判断类型,类似C# 的 var
  • Lua中的一个变量可以随便赋值 —自动识别类型。
a = nil
a = 1
  • 复杂数据类型
  • 函数 function
  • 表 table
  • 数据结构 userdata
  • 协同程序 thread(线程)

2.1 nil类型

  • 空类型。类似于C#中的null。
a = nil

2.2 number类型

  • 所以的数值都是number。
a = 1
a = 1.2

2.3 string类型

  • 字符串的声明 使用单引号或者双引号包裹。
  • Lua里没有 char。
a = "123"
a = '123'

2.4 boolean类型

a = true
a = false

2.5 type函数

  • 通过type函数我们可以得到变量的类型。
  • 打印结果为变量类型。
  • type函数自身的返回值为string
a = 1
print(type(a))

2.6 没有声明的变量

  • Lua中使用没有声明过的变量,不会报错,默认值为nul。
print(b)

第3章 字符串操作

3.1 获取字符串长度

  • 一个汉子占3个长度
  • 英文字符占1个长度
s = "aBcdEfG字符串"
print(#s)
--输出结果为16

3.2 字符串多行打印

  • Lua中也支持转义字符 \n
print("123\\n123")
  • 第二种方法
s = [[我是
jo
ker
]]
print(s)

3.3 字符串拼接

  • 字符串拼接通过**..**
  • ..可以与任何简单类型拼接
print("123" .. "456")

s1 = "123123"
s2 = 111
print(s1 .. s2)
--输出结果为123123111

3.4 占位符

  • 常用的几个。 %d :与数字拼接 %a :与任何字符拼接 %s 与字符配对 …
print(string.format("我是joker,今年%d岁了", 18))

3.5 其他类型转字符串

a = true
print(tostring(a))

3.6 字符串提供的公共方法

3.6.1 小写转大写的方法

  • 原本的变量不会改变,只是打印出来的改变了。
str = "abCdefg"
print(string.upper(str))

3.6.2 大写转小写

  • 同上。
str = "abCdefg"
print(string.lower(str))

3.6.3 翻转字符串

  • 同上。
str = "abCdefg"
print(string.reverse(str))

3.6.4 字符串索引查找

  • Lua字符串从1开始而并非0。
  • Lua可以多返回值。
str = "abCdefg"
print(string.find(str, "Cde"))
--输出为3  5
print(string.find(str, "C"))
--输出为3  3

3.6.5 截取字符串

str = "abCdefg"
print(string.sub(str, 3))
--输出为Cdefg
print(string.sub(str, 3, 4))
--有重载方法。输出为Cd

3.6.6 字符串重复

str = "abCdefg"
print(string.rep(str, 2))
--输出为abCdefgabCdefg

3.6.7 字符串修改

  • 第二个参数为修改的次数。
str = "abCdefg"
print(string.gsub(str, "Cd", "**"))
--输出为ab**efg  1

str = "abCdefgCd"
print(string.gsub(str, "Cd", "**"))
--输出结果为ab**efg**  2

3.6.8 字符转ASCII码

  • 第二个参数为脚标。
a = string.byte("Lua", 1)
print(a)
--输出结果为76

3.6.9 ASCII码转字符

a = 76
print(string.char(a))
--输出结果为L

第4章 运算符

4.1 算数运算符

        • / % ^
  • 没有自增自减 ++ – –
  • 没有复合运算符 += -= /= *= %=
  • 字符串可以进行算数运算符操作,会自动转成number。
print("123.4" + 1)
--输出为124.4
  • ^ Lua中该符号是幂运算。
print("幂运算" .. 2 ^ 5)
--输出为幂运算32

4.2 条件运算符

  • < >= <= == ~=

  • 不等于是~=

4.3 逻辑运算符

  • C#中:&& || !
  • Lua中:and or not
  • Lua中也遵循逻辑运算的 “短路” 规则。

4.4 位运算符

  • 不支持位运算符 & |
  • 需要我们自己实现

4.5 三目运算符

  • 不支持三目运算符 ? :

第5章 条件分支语句

  • Lua中没有switch语法,需要自己实现

5.1 if语句

  • 单分支
  • if 条件 then……end
a = 9
if a > 5 then
		print("123")
end
  • 双分支
  • if 条件 then……else……end

a = 9
if a < 5 then
		print("123")
else
		print("321")
end
  • 多分支
  • if 条件 then……elseif 条件 then…….else……end
  • elseif 一定要连这写,否则报错。
a = 9
if a < 5 then
		print("123")
elseif a == 6 then
		print("6")
end

第6章 循环

6.1 while语句

  • while 条件 do……end
num = 0
while num < 5 do
		print(num)
		num = num + 1
end

6.2 do while 循环

  • repeat……until 条件 (注意:条件是结束条件
num = 0
repeat
		print(num)
		num = num + 1
until num > 5 -- 满足条件跳出 结束条件 C#为进入条件

6.3 for循环

for i = 1, 5 do --默认递增 i会默认+1
		print(i)
end
  • 如果想自定义增量 直接逗号后面写
for i = 1, 5, 2 do --如果想自定义增量 直接逗号后面写
		print(i)
end

第7章 函数

7.1 无参数无返回值

  • function 函数名()……end
--F1() 这里调用会报错 Lua要按自顶向下的顺序运行
function F1()
		print("F1函数")
end
F1()
  • 第二种写法。
  • 有点类似 C#中的 委托和事件。
F2 = function()
		print("F2函数")
end
F2()

7.2 有参数

  • 不需要写参数类型。
  • 如果你传入的参数和函数个数不匹配,不会报错只会补空nil或者丢弃。
function F3(a)
		print(a)
end
F3(1)
F3("123")
F3(true)
--如果你传入的参数和函数个数不匹配,不会报错只会补空nil或者丢弃
F3() --默认nil
F3(1,2,3)

7.3 有返回值

  • 无需声明返回类型
function F4(a)
		return a
end

temp = F4(1)
  • 多返回值时,在前面声明多个变量来接取即可。
  • 如果变量不够,不影响,直接取对于位置的返回值。
  • 如果变量多了,不影响,直接赋值nil。
function F4(a)
			return a, "123", true
end

temp, temp2, temp3 = F4("1")

7.4 函数的类型

  • 函数类型就是function
F5 = function()
		print("123")
end
print(type(F5))
--输出为function

7.5 函数的重载(Lua不支持重载)

  • 重载:函数名相同,参数类型不同或者参数个数不同。
  • Lua中不支持重载,默认调用最后一个声明的函数。

7.6 变长参数

  • 变长参数使用,用一个表存起来再用。
  • 变长参数没有规定传入类型。
function F7(...)
		arg = {...}
		for i = 1, #arg do
				print(arg[i])
		end
end
F7(1, "123", true, 4, 5, 6)--没有规定类型。

7.7 函数嵌套

function F8()
		F9 = function()--可简写,直接return,不用取名。
				print(123)
		end
		return F9
end

f9 = F8()
f9()
--输出为123
  • 函数闭包。
function F9(x)
	--改变传入参数的生命周期
		return function(y)
				return x + y
		end
end

f10 = F9(10)
print(f10(5))
--输出为15

第8章 复杂数据类型——表

  • 所以的复杂类型都是table(表)

8.1 数组

  • 可以传入任何类型。
  • Lua中索引从1开始。
  • #是通用的获取长度的关键字。
  • 在打印长度的时候nil被忽略。
  • 如果表(数组)中,某一位变成nil 会影响#获取的长度,遇到nil会中断后续的长度。
a = {1, 2, 3, 4, "1231", true, nil}
print(a[1])
--输出为1

print(#a)
--输出为6

8.2 数组的遍历

a = {1, 2, 3, 4, "1231", true, nil}
for i = 1,#a do
	print(a[i])
end

8.3 二维数组

  • 二维数组本质上都是基于表。
a = {{1, 2, 3}, {4, 5, 6}}
print(a[1][1])

8.4 二维数组的遍历

a = {{1, 2, 3}, {4, 5, 6}}
for i = 1, #a, do
		b = a[i]
		for j = 1, #b do
				print(b[j])
		end
end

8.5 自定义索引

  • 自定义索引不算入长度。
  • 一般不建议自定义索引。
aa = {[0] = 1, 2, 3, [-1] = 4, 5}
print(aa[0])
--输出为1
print(aa[-1])
--输出为4
print(#aa)
--长度为3 自定义索引不算入长度。

注意深坑:中间索引断了一个数就输出索引最大值(断了[3] = 3),中间断了2个数就不认后面的索引。

aa = {[1] = 1, [2] = 2, [4] = 4, [5] = 5}
print(#aa)
--输出为5
aa = {[1] = 1, [2] = 2, [5] = 5, [6] = 6}
print(#aa)
--输出为2

第9章 迭代器遍历

  • 迭代器遍历,主要是用来遍历表的。
  • #得到长度,其实并不准确,一般不用#来遍历表

9.1 ipairs迭代器

  • ipairs遍历,还是从1开始往后遍历的,小雨等于0的值得不到
  • 只能找到连续索引的键,如果中间断序了,它也无法遍历出后面的内容。
  • 和#类似。
  • 使用前提:保证表中都是连续的,否则使用pairs迭代器。
a = {[0] = 1, 2, [-1] = 3, 4, 5}
for i, k in ipairs(a) do
		print("ipairs遍历键值"..i.."_"..k)
end
--输出为1_2 2_4 3_5
a = {[0] = 1, 2, [-1] = 3, 4, 5,[5] = 6}
for i, k in ipairs(a) do
		print("ipairs遍历键值"..i.."_"..k)
end
--输出为1_2 2_4 3_5 4_6

9.2 pairs迭代器遍历

  • 它能够把所有的键都找到,通过键可以得到值。
a = {[0] = 1, 2, [-1] = 3, 4, 5,[5] = 6}
for i, v in pairs(a) do
		print("pairs遍历键值"..i.."_"..v)
end
--输出为1_2 2_4 3_5 0_1 -1_3 5_6

9.3 迭代器遍历键

a = {[0] = 1, 2, [-1] = 3, 4, 5,[5] = 6}
for i in pairs(a) do
		print("pairs遍历键"..i)
end
--输出为1 2 3 0 -1 5

9.4 迭代器遍历——虚拟变量

  • 一种特殊写法,本质上也是先获得键。
for _, v in pairs(a) do
		print(v)
end

第10章 复杂数据类型——表2

10.1 table表实现字典

10.1.1 字典的声明

  • 字典是由键值对构成。
a = {["name"] = "joker", ["age"] = 14, ["1"] = 5}

10.1.2 字典的访问

  • 访问单个变量,用中括号填键来访问。
print(a["name"])
print(a["age"])
print(a["1"])
  • 还可以类似 . (dot)成员变量的形式得到值。
  • 虽然可以通过 . (dot) 成员变量的形式得到值,但是不能是数字。
print(a.name)
print(a.age)

print(a.1)
--报错
print(a["1"])
--正常

10.1.3 字典的修改

a["name"] = "TLS"
print(a["name"])
print(a.sex)

10.1.4 字典的增加

  • 新增只需要加新的键。
a["sex"] = false
print(a["sex"])
print(a.sex)

10.1.5 字典的删除

  • 赋nil值可以认为是删除。
a["sex"] = nil
print(a["sex"])
print(a.sex)

10.1.6 字典的遍历

  • 如果要模拟字典遍历一定要用pairs。
  • 可以传多个参数,一样可以打印出来。
for k, v inpairs(a) do
		print(k,v)
end
--键值对同时遍历

for k in pairs(a) do
		print(k)
		print(a[k])
end
--只遍历其中一个

10.2 table表实现类和结构体

  • Lua中是默认没有面向对象对,需要我们自己来实现。

10.2.1 类

  • 成员变量 成员函数…
  • C#要是使用类,实力化对象new,静态直接 . (dot)
  • Lua中类的表现,更像是一个类中有很多静态变量和函数。
  • 在表内部函数中调用表本身的属性或者方法,一定要指定是谁,使用表名 . 属性 或 表名 . 方法。
  • 第二种能够在函数内部调用自己属性或者方法的 方法,把自己作为一个参数传进来在内部访问。
Student = {
	--年龄
	age = 1,
	--函数
	sex = true,

	--成长函数
	Up = function()
		--这样写 这个age和表中的age没有任何关系,它是一个全局变量
		--print(age)
			print(Student.age)
			print("我成长了")
	end,
	--学习函数
	Learn = function(t)
		--第二种方法
			print(t.sex)
			print("好好学习,天天向上")
	end
}

10.2.2 类中方法的调用

print(Student.age)
Student.Up()
  • Lua中 . 和 : 有区别。
  • 冒号调用方法,会默认把调用者 作为第一个参数传入方法中。
Student.Learn(Student)
Student:Learn()

10.2.3 类中成员的增加

  • 声明表过后,在表外取声明表有的变量和方法。
  • 建议都使用第三种方法。
Student.name = "joker"
  • 函数也可以这样。
Student.Speak = function()
		print("说话")
end
  • 第二种方法
function Student.Speak2()
		peint("说话2")
end
  • 第三种方法 使用冒号(: )声明
  • Lua中,关键字 self 表示默认传入的第一个参数
function Student:Speak2()
		print(self.name .. "说话")

10.3 表的公共操作

  • 表中 table 提供的一些公共方法。
  • 例子
t1 = { {age = 1, name = "123"}, {age = 2, name = "345"} }
t2 = { name = "joker", sex = true }

10.3.1 表的插入

  • 把t2插入到t1。
table.insert(t1, t2)

10.3.2 表的删除

  • remove方法 传表进去,会移除最后一个索引的内容。
table.remove(t1)
  • remove方法 传两个参数,第一个参数是要移除内容的表,第二个参数是要移除内容的索引。
table.remove(t1, 1)

10.3.3 表的排序

  • 传入要排序的表默认升序排序。
t3 = {5, 2, 7, 9, 5}
table.sort(t3)
for _, v in pairs(t2) do
		print(v)
end
--输出2 5 5 7 9
  • 传入两个参数,第一个是用于排序的表,第二个是排序规则函数。
  • 这里是降序。
t3 = {5, 2, 7, 9, 5}
table.sort(t3, function(a, b)
		if a > b then
			return true
		end
end)
for _, v in pairs(t2) do
		print(v)
end
--输出9 7 5 5 2

10.3.4 表的拼接

  • 连接函数concat用于拼接表中的元素,返回值是一个字符串。
  • 一般只用来拼接字符串和数字。
tb = {"123", "456", "789", "10101"}
str = table.concat(tb, ",")
print(str)
--输出为123,456,789,10101

第11章 多脚本执行

11.1 全局变量和本地变量

11.1.1 全局变量

  • 这些都是全局变量,包括在循环里面声明
a = 1
b = "123"
for i = 1, 2 do
		c = "joker"
end
print(c)
--输出joker 仍然可以用

11.1.2 本地变量

  • 本地(局部)变量大关键字 local。
  • 只在对应语句块有作用
for i = 1, 2 do
		local d = "joker"
end
print(d)
--输出为空

11.2 多脚本执行

  • 关键字 require(“脚本名”) / require(‘脚本名’)。
  • 不同文件需要加上路径。
  • 只要运行过就可以使用到其他脚本的全局变量,但是本地变量不可以。
require("Test")
print(testA)
--输出123
print(testLocalA)
--输出为空
--Test文件
print("Test测试")
testA = “123”
local testLocalA = "456"
  • 如果是require加载执行的脚本,加载一次过后不会再被执行。
require("Test")
require('Test')
--只执行一次

11.3 脚本卸载

  • 关键字package.loaded[“脚本名”]
  • 返回值是boolean,意思是该脚本是否被执行。
print(package.loaded["Test"])
  • 卸载以及执行过的脚本
package.loaded["Test"] = nil

11.4 大G表(_G表)

  • _G表是一个总表(table)他将我们声明的所有全局的变量都存储在其中。
  • 本地变量,加了local的变量是不会存到大_G表中的。

11.5 本地变量特殊调用

  • require执行一个脚本时,可以在脚本最后返回一个外部希望获取的内容。
local testLA = require("Test")
print(testLA)
--输出为123
--Test文件
print("Test测试")
testA = “123”
local testLocalA = "456"

--return出去
return testLoaclA

第12章 特殊用法

12.1 多变量赋值

a, b, c = 1, 2, "123"
  • 多变量赋值,如果后面的值不够,会自动补空。
a, b, c = 1, 2
--c为nil值
  • 如果后面的值多了,会自动省略。
a, b, c = 1, 2, 3, 4, 5, 6
--456省略了

12.2 多返回值

  • 多返回值时,用几个变量接,就有几个值。
  • 如果少了,就少接几个,如果多了就自动补空。
function Test()
		return 10, 20, 30, 40
end

12.3 and or

  • 逻辑与 逻辑或。
  • and or 他们不仅可以连接 boolean 任何东西都可以用来连接。
  • 在Lua中,只有nil和false才认为是假。
  • “短路”对于and来说,有假则假,对于or来说,有真则真。
  • 所以他们只需要判断第一个是否满足,就会停止计算了。
print(1 and 2)
--输出2
print(0 and 1)
--输出1
print(nil and 1)
--输出nil
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

12.3.1 三目运算符

  • Lua不支持三目运算符。
  • 运用“短路”实现? : 。
x = 3
y = 2
local res = (x > y) and x or y
print(res)
--(x > y) and x ——> x
--x or y ——> x
x = 1
y = 2
local res = (x > y) and x or y
print(res)
--(x > y) and x ——> (x > y)
--(x > y) or y ——> y

第13章 协同程序

13.1 协程的创建

13.1.1 create创建(常用方式)

  • create创建协程的本质是一个thread(线程)对象。
  • coroutine.create()
fun = function()
		print(123)
end

co = coroutine.create(fun)

13.1.2 wrap创建

  • wrap创建协程的本质是一个function对象。
  • coroutine.wrap
co2 = coroutine.wrap(fun)

13.2 协程的运行

13.2.1 resume运行

  • 第一种方式对对应的是通过create创建的协程。
  • coroutine.resume()
coroutine.resume(co)

13.2.2 fun运行

  • 第二种方式对应的是通过wrap创建的协程。
  • 因为返回的是函数,所以直接当成函数调用就行。
co2()

13.3 协程的挂起

fun2 = function()
		while true do
				print(123)
				--协程的挂起函数
				coroutine.yield()
		end
end

co3 = coroutine.create(fun2);
--每启动一次只会启动一次
coroutine.resume(co3)

  • yield可以有返回值。
  • 也可以有多个返回值。
  • 用resume运行。默认第一个返回值是协程是否启动成功。
fun2 = function()
		local i = 1
		while true do
				print(i)
				i = i + 1
				coroutine.yield(i)
		end
end

co3 = coroutine.create(fun2);
isOk, tempI = coroutine.resume(c03)
--输出true  1
  • 用fun调用,没有默认返回值,直接返回返回值。
co4 = coroutine.wrap(fun2)
print("返回值" .. co4())

13.4 协程的状态

  • coroutine.status(协程对象)
  • dead 结束(没有挂起)
  • suspended 暂停(挂起了)
  • running 进行中
  • 这个函数可以得到当前正在运行的协程的线程号。
coroutine.running()

第14章 元表

14.1 元表概念

  • 任何表变量都可以作为另一个表变量的元表。
  • 任何表变量都可以有直接的元表(爸爸)。
  • 当我们子表中进行一些特定操作时,会执行元表中的内容。

14.2 设置元表

  • setmetatable(子表, 元表)
meta = {}
myTable = {}
setmetatable(myTable, meta)

14.3 特定操作

14.3.1 特定操作-__tostring

  • 当子表要被当做字符串使用时,会默认调用这个元表中的__tostring方法。
meta2 = {
		__tostring = function()
				return "joker"
		end
}

myTable2 = {
}

setmetatable(myTable2, meta2)

print(myTable2)
--输出为joker
  • 元表调用子表的内容
meta2 = {
		--参数t默认把子表传入
		__tostring = function(t)
				return t.name
		end
}

myTable2 = {
		name = "joker2"
}

setmetatable(myTable2, meta2)

print(myTable2)
--输出为joker2

14.3.2 特定操作-__call

  • 当子表被当做一个函数来使用时,会默认调用这个__call中的内容。
  • 只有设置了元表和有__call函数才能够这样调用。
meta3 = {
		__call = function()
				print("MkLeo")
		end
}

myTable3 = {
		name = "Tweek"
}

setmetatable(myTable3, meta3)

myTable3()
--输出为MkLeo
  • __call的参数,第一个参数是表自己,第二个参数才是1。
  • a相当于myTable3本身,然后调用了自己的__tostring方法。有点像 “:”调用。
meta3 = {
		__tostring = function(t)
				return t.name
		end,
		__call = function(a, b)
				print(a)
				print(b)
				print("MkLeo")
		end
}

myTable3 = {
		name = "Tweek"
}

setmetatable(myTable3, meta3)

myTable3(1)
--输出为Tweek 1 MkLeo

14.3.3 特定操作-运算符重载

  • __add相当于运算符重载,当子表使用+运算符时,会调用该方法。
  • 使用条件运算符来比较两个对象,这两个对象的元表一定要一致才能准确调用方法。
  • 其他运算符同理。
    • +运算符 __add
    • -运算符 __sub
    • *运算符 __mul
    • /运算符 __div
    • %运算符 __mod
    • ^运算符 __pow
    • ==运算符 __eq 返回boolean
    • <运算符 __lt 返回boolean
    • <=运算符 __le 返回boolean
    • ..运算符 __concat
meta4 = {
		__add = function(t1, t2)
				return 5
		end
}

myTable4 = {}

setmetatable(myTable4, meta4)

myTable5 = {}

print(myTable4 + myTable5)
--输出5
  • 有参数时
meta4 = {
		__add = function(t1, t2)
				return t1.age + t2.age
		end
}

myTable4 = {age = 1}

setmetatable(myTable4, meta4)

myTable5 = {age = 2}

print(myTable4 + myTable5)
--输出3

14.3.4 特定操作-__index和__newIndex

  • __index 当子表中找不到某个属性时,会到元表中 __index指定的表去找属性。
  • __index的赋值,写在表外面来初始化(写里面有坑)。
meta6 = {
		age = 1

		--元表指定的表
		meta6.__index = {age = 2}
		--下面这种写法是坑,为nil值
		--meta6.__index = meta6
}

--这样也是可以的
--meta6.__index = meta6

myTable6 = {}

setmetatable(myTable6, meta6)

print(myTable6.age)
--输出为1
  • __index的嵌套
meta6Father = {
		age = 1
}
meta6Father.__index = meta6Father

meta6 = {}
meta6.__index = meta6

myTable6 = {}
setmetatable(meta6, meta6Father)
setmetatable(myTable6, meta6)

14.3.4 特定操作-__newIndex

  • __newIndex 当赋值时,如果赋值一个不存在的索引,那么会把这个值赋值到newIndex所指的表中,不会修改自己。
meta7 = {}
myTable7 = {}
setmetatable(myTable7, meta7)
myTable7.age = 1
print(myTable7.age)
--输出为nil

14.4 获取元表

  • getmetatable(子表)
  • 得到元表的方法。

14.5 rawget方法

  • rawget当我们使用它时,会去找自己身上有没有这个变量,且只能找自己。
--在元表找
print(myTable.age)
--只找自己
print(rawget(myTable6, "age"))

14.6 rawset方法

  • rawset该方法会忽略__newIndex的设置,只会改自己的变量。
rawset(myTable7, "age", 2)
--输出2

第15章 Lua面向对象

15.1 封装

  • 面向对象 类 其实都是基于 table来实现。
  • 元表相关的知识点。
  • 下面例子是用Lua模拟C#的new对象。
Object = {}
Object.id = 1

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

--冒号 是会自动将调用这个函数的对象作为第一个参数传入的写法
function Object:new()
		--self代表的是 我们默认传入的第一个参数
		--对象就是变量 返回一个新的变量
		--返回出去的内容 本质上就是表对象
		local obj = {}
		--元表知识 __index 当找自己的变量找不到时就会去找元表中__index指向的内容
		self.__index = self
		setmetatable(obj, self)
		return obj
end
  • 调用上面代码测试。
local myObj = Object:new()
print(myObject.id)
--输出为1
myObject:Test()
--输出为1

--对空表中 声明一个新的属性 叫做id 并没有修改Object的内容
myObject.id = 2
print(Object.id)
--输出为1

myObject.id = 2
myObject:Test()
--输出为2 相当于把自己传入了Test()

15.2 继承

  • C# class 类名 : 继承类
  • _G知识点补充
_G["a"] = 1
_G.b = "123"
  • 写一个用于继承的方法
Object = {}
Object.id = 1

function Object:subClass(className)
		-- _G是总表,所有声明的全局变量都以键值对的形式存在其中
		_G[className] = {}
		--写相关继承的规则
		--用到元表
		local obj = _G[className]
		self.__index = self
		setmetatable(obj, self)
end
  • 调用
  • p1元表是Person Person元表是Object
  • 顺序:p1找元表的__index,找到Person自己,Person再找元表的__index,找到Object自己。
Object:subclasee("Person")
local p1 = Person:new()
print(p1.id)
--输出为1

15.3 多态

  • 相同行为,不同表像,就是多态。
  • 相同方法,不同执行逻辑,就是多态。
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
  • 构建base
Object = {}

function Object:subClass(className)
		_G[className] = {}
		local obj = _G[className]
		self.__index = self

		--子类定义一个base属性代表父类
		obj.base = self

		setmetatable(obj, self)
end
  • 调用 (注意有坑)
GameObject:subClass("Player")
function Player:Move()

		--坑的主要问题所在
		--这个base指的是 GameObject表
		--这种方式调用相当于是把基类表作为第一个参数传入了方法中
		--避免把基类表 传入到方法中 这样相当于就是公用一张表的属性了
		self.base:Move()

end

local p1 = Player:new()
p1.Move()
--输出1 1

--目前这种写法有坑,不同对象使用的成员变量是相同的成员变量,不是自己的
local p2 = Player:new()
p2:Move()
--输出2 2 违背了面向对象

p1:Move()
--输出3 3 违背了面向对象
  • 改进方法self.base.Move(self)
GameObject:subClass("Player")
function Player:Move()
		--我们要执行父类逻辑,我们不要直接使用冒号调用
		--要通过 . 调用,然后自己传入第一个参数
		self.base.Move(self)
end

15.4 面向对象实现

  • 万物之父 所有对象的基类 Object
Object = {}

--实力化方法
function Object:new()
		local obj = {}
		--给空对象设置元表,以及 __index
		self.__index = self
		setmetatable(obj, self)
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继承Object
GameObject:subclass("Player")
--多态 重写类GameObject的Move方法
function Player:Move()
		--调用父类方法 用 . 自己传第一个参数
		self.base.Move(self)
end

--实力化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章 自带库

16.1 时间相关

  • 系统时间
print(os.time())
  • 自己传入参数 得到时间
print(os.time({year = 2014, month = 8, day = 14}))
  • os.data(“*t”)
loacl nowTime = os.data("*t")
for k, v in pairs(nowTime) do
		print(k, v)
end
print(nowTime.hour)

16.2 数学运算相关

  • 绝对值
print(math.abs(-11))
  • 弧度转角度
print(math.deg(math.pi))
  • 三角函数 传弧度
print(math.cos(math.pi))
  • 向下向上取整
print(math.floor(2.6))
print(math.ceil(5.2))
  • 最大最小值
print(math.max(1, 2))
print(math.min(4, 5))
  • 小数分离 分成整数部分和小数部分
print(math.modf(1.2))
  • 幂运算
print(math.pow(2, 5))
  • 随机数
  • 先设置随机数种子
math.randomseed(os.time())
print(math.random(100))
  • 开方
print(math.sqrt(4))

16.3 路径相关

  • Lua脚本加载路径
print(package.path)
package.path = package.path .. ";C:\\\\"
print(package.path)

第17章 Lua垃圾回收

17.1 垃圾回收关键字collectgarbage

  • 获取当前Lua占用内存数,K字节,用返回值*1024就可以得到具体的内存占用字节数。
test = {id = 1, name = "123123"}
print(collectgarbage("count"))
  • 进行垃圾回收 理解有点像C#的GC。
  • Lua中的机制和C#中垃圾回收机制很类似 解除羁绊 就是变垃圾。
collectgarbage("collect")
  • Lua中有自动定时进行GC的方法。
  • Unity中热更新开发,尽量不要去用自带垃圾回收。

本文来自投稿,不代表Crestruction立场,如若转载,请注明出处:https://crestruction.org/archives/c-tech/1110/

发表评论

登录后才能评论