Lua笔记

lua中使用类中的方法来访问自己类的属性 几种方式

print("--------分割线---------")
Student = {
	age = 18,
	["name"] = "老王",
	-- 写在表里面的方法,只能使用方法名 = 函数
	[[--
	 在类的内部与外部想要增添修改该类的方法时
	 都不允许下面的写法,除非是使用冒号--]]
	-- 不能直接声明函数function Fun(),否则会报错
	
	--1.加类名.属性
	printName = function()
		print("名字是" .. Student.name);
	end
	--2.传入参数,然后通过外部调用传入
	printName2 = function(a)
		print("名字是" .. a.name)
	end
	--3.使用冒号传入自己
}
--接第二种方法
Student.printName2(Student)
--接第三种方法,使用冒号就不需要传参数了,他会默认传入自己
Student:printName2()

--4.在类的外部添加方法
--注意此时只能用冒号,无参数,使用self表示默认传入的第一个参数
function Student:Speak()
	print(self.name)
end
--接第四种方法,这里只能使用冒号
Student:Speak()

点和冒号的区别:点是正常调用,冒号表示把自己作为第一个参数传入
注意:self不等同于this

Lua中的元方法

__index:首先需要设置元表(以下简称为父子表)。当子表想要使用某个变量,但是却找不到时,就会到父表的__index中查找,并且:如果父表的__index是一个函数,则会调用这个函数;如果父表的__index是一个表,则会到这个表中再次查找那个属性。如下所示

local parent = {}
parent.__index = function()
    print("子表想要用某个不存在的属性,即为空的时候调用")
end

local son = {}
setmetatable(son, parent)

--此时会调用 parent的__index
local a = son.a

__index可以有带参数跟返回值的,参数表示子表。有2个参数:tab:调用者 k:调用者的键
__newindex:对某个不存在的变量赋值时会调用,注意newindex是全小写。有3个参数:tab:调用者 k:调用者的键 v:调用者的值

parent.__index = function()
    print("子表想要用某个不存在的属性,即为空的时候调用")
    return 1
end

parent.__newindex = function(tab, k, v)
    print("子表对不存在的值赋值时调用")
end

local son = {}

setmetatable(son, parent)

son.func = function()
    print("OK")
end

print(son.func)

上面的输出会是1,因为父表中有__newindex,对son.func赋值时会被__newindex代替,导致赋值失败。打印的时候,又因为son.func为空,则还会调用__index函数,返回1
注意__newindex的返回值没有意义

lua中的一些细节

1.for循环中的条件只能写i在==结果时,这次遍历完就跳出,不可以写别的for i = 1, 5, 1 do 表示如果i<=5那么会一直循环
2.t = {}, #t查找的表中数量只有在表是当数组用,并且数组是连续的时候,才能返回正确的个数,如果中间断开,那么后面的就会无效;t[“xx”], t.xx 这些都无法被#t计数d
3.变长参数类型为string,要使用的话需要先用一个表将…存起来

local function foo2(...)
    local t = {...}
    print(t[1])
    print(type(...))
end
foo2("XD", 222, 123)	-->XD, 	string

4.ipairs和pairs区别
ipairs只能用于遍历序列(没有元素为空的数组),并且中间不允许有其他非数组的键值对,否则直接停止遍历。ipairs的遍历是顺序的

--结果是只输出"XD", 2
local tab = {[1] = "XD", [2] = 2, ["3"] = 3, [4] = 'w'}
print(#tab)

for k, v in ipairs(tab) do
    print(k, v)
end

pairs可适用于序列和有键值对形式的,可以允许序列和键值对混合,并且当遍历遇到nil时,不会停止遍历,而会跳过。但是pairs无法保证顺序,每次运行时都可能会有不同的顺序

5.lua中的逻辑运算符
lua的逻辑运算符于C#返回结果差很多,C#是返回true,false,而lua则是返回具体的值

a and b:当a为真时返回b,当a为假时,返回a <=> 条件表达式 a?b:a
a or b:当a为真时返回a, 当a为假时返回b <=>条件表达式 a?a:b
not a:当a为真时返回假,当a为假时返回真 <=>条件表达式 !a

6.变长参数 …
变长参数不可直接使用,如果直接使用,则只是一个string类型,并且只保存了第一个参数

function _M.Test(...)
    local tab = ...
    print("类型是==", type(tab)) --> string
    print(tab) --> 只输出了 XD
end

_M.Test("XD", "qwq", false, 112)

不过print(…)是可以输出所有参数的,可能是做了特殊处理
要使用变长参数,需要用一个表接收他: local table = {…},这样就可以通过遍历获取所有值;
或者使用多个参数接收:local a, b, c = …

7.pcall和xpcall
pcall有2个参数,第一个参数是要调用的函数,第二个参数是变长参数,会传给要调用的函数。
pcall有2个返回值,第一个返回值是是否正确执行,没有异常返回true,发生异常会返回nil;
第二个返回值是错误堆栈,出现异常才会有这个返回值。如下

local function test(v1)
	print("v1==", v1) -->XD
	local a
	a[1] = 5
end

local r1, r2 = pcall(test, "XD")
print("r1==", r1, "r2==", r2) -->r1==nil, r2==堆栈信息..

xpall有3个参数,第一个参数是要调用的函数,第二个参数是异常处理函数,第三个参数是变长参数,会传给要调用的函数
xpall有1个返回值,是否正确执行。
需要注意一点的是,异常处理函数不能自己传参数过去,只会有一个参数,为异常堆栈信息

local function test(v1)
	print("v1==", v1)	-->XD
	local a
	a[1] = 5
end

local function con(err)
	print("Error!", err)	-->Error! 堆栈信息..
end

local r1 = xpall(test, con, "XD")
print("r1==", r1)	-->nil

9.assert断言
assert需要传入2个参数,第一个参数是bool值,第二个参数是提示信息。bool值是false的时候,会中断代码执行,打印提示信息和调用堆栈。
assert和pcall、xpall不一样,assert会直接中断程序,而pcall,xpcall则不会自动中断

10.table unpack和pack
table.pack:传入多个参数,并返回一张序列表,表里另外有一个字段叫做n,表示参数个数。传入nil有效,会被n计数
table.unpack:将序列表转换成多返回值返回,注意必须是序列才可以,调用了unpack,原来的n将不会被返回

require 函数解释

require 会有一个默认的加载路径,为package.path,可以自己添加加载路径,不允许相对路径,如…/
require 加载完的文件,其返回值会存在package.loaded表中,key为路径。如下

--[[ MyTest1
local test = {}
print("test---- require")   会输出
test.xd = "XD"
return test
--]]

local module = "Modules.MyTest.MyTest1"
local t1 = require(module)
print(package.loaded[module].xd) --> "XD"

需要注意的是,如果require成功,则以后再require这个路径,就会到package.loaded中返回,而不再调用要请求的脚本的代码。
两次require的结果是同一个对象。如下

--[[ MyTest1
local test = {}
print("test---- require")   只会输出1次
test.xd = "XD"
return test
--]]
local module = "Modules.MyTest.MyTest1"
local t1 = require(module)
t1.xd = "XD123"
print(t1.xd) --> XD123
local t2 = require(module)
print(t2.xd) --> XD123

package.loaded[xx] = nil 可删除require返回值,下次再require则会再次调用要请求的脚本的代码,且原来已声明的表(t1表)不会被删除,依然存在,并且两个表(t1和t2表)不再有关联。如下

--[[ MyTest1
local test = {}
print("test---- require")   会输出2次
test.xd = "XD"
return test
--]]

local module = "Modules.MyTest.MyTest1"
local t1 = require(module)
t1.xd = "XD123"
print(t1.xd) --> XD123
package.loaded[module] = nil

local t2 = require(module)
print(t2.xd) --> XD
t2.xd = "t2XD"
print(t1.xd)  --> XD123

 

环境_ENV(5.2版本之后)

lua中其实不存在全局变量,所谓的全局变量只是一种语法糖。
lua全局变量编译的规则:全局变量在编译时,会被自动转换为_ENV.xx。所以所有的全局变量其实只是_ENV表中的一个成员。
_ENV本质也是一张表,所以可以重新赋值,重新赋值后,原来其他的全局变量都会丢失,相当于构建了一个新的环境。原因如下

local rawENV = _ENV
_ENV = {}
print("OK") --> 代码报错,因为_ENV["print"]为nil

--如果想要调用print,则可以使用原来存放的rawENV
--local rawENV = _ENV
--_ENV = {}
--rawENV.print("OK") --> OK

如果想要还原初始的环境,则只需要将_ENV重新赋值为原本的就可以

local rawENV = _ENV
_ENV = {}
rawENV.print(print) --> nil
_ENV = rawENV
print("OK") --> OK

这个机制使得可以做一些特殊操作,比如

local parent = {
	--这样在访问到全局的空表时,可以提示信息
    __index = function(tab, k)
	    print("Error!! not this Table===", tab, k)
    end
}

setmetatable(_ENV, parent)
--临时重载math.abs函数,并且可以还原
local rawENV = _ENV
_ENV = {}
math = {}
function math.abs(a)
	return a
end
local r1 = math.abs(-1)
_ENV = rawENV
local r2 = math.abs(-1)
print("r1==", r1) --> -1
print("r2==", r2) --> 1

协程的基本用法

--1.创建一个协程,但是还没有启动
local co = coroutine.create(function(a, b)
    print("a==", a, "b==", b)	-->a==	XD	b==	1
    local yieldRet1, yieldRet2 = coroutine.yield("co1")	--3.执行到这里时,遇到yield,协程挂起,可返回参数"co1"
    print("yieldRet1==", yieldRet2, "yieldRet2==", yieldRet2)	-->yieldRet1==	XD2	yieldRet2==	2
end)

--2.启动这个协程,并且可以传参数进协程 "XD", 1
local resu, v1 = coroutine.resume(co,  "XD", 1)

--4.从上次挂起的地方继续执行协程,还可传入参数
print("resu==", resu, "v1==", v1)	-->resu==	true	v1==	co1
coroutine.resume(co, "XD2", 2)

下面解释每段代码
1.创建一个协程,但还没启动。结果会返回一个协程对象
2.启动或继续执行协程,这里是启动。coroutine.resume(co, “XD”, 1) 参数1:协程对象;其他参数:协程函数所需的参数
3.协程函数开始走,走到yield函数时,挂起协程,后面的代码暂停运行。yield可传参数,作为coroutine.resume的返回值。resume返回值1:协程是否执行正常;其他返回值:yield传入的参数
4.再次调用resume,从上次yield的地方返回,返回值是resume传入的参数。然后继续往后走

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值