C#使用者的lua学习笔记——多脚本 协程 特殊用法 元表

C#使用者的lua学习笔记——多脚本 协程 特殊用法 元表

多脚本执行

前面我们曾经谈到作用域的问题 对于lua来说如非local那么所有的都是全局

这一点在多脚本的情况下仍然是成立的 对于一个在该脚本local的变量 自然是不可以被其它脚本调用的

--加载脚本
--关键字 require("脚本名") require(‘脚本名’)
require("Test")

--如果是require加载执行的脚本 加载一次后不会被再执行
print(package.loaded["Test"])
--返回值是bool 意思是该脚本是否被执行
--卸载脚本 即置空 但一般不需要特意卸载
package.loaded["Test"] =nil

_G(大G表)

_G表 是一个table

将我们声明的所有全局变量都存储在其中

for k,v in pairs(_G) do
print(k,v)
end

加了local的变量是不会存到大G表中的


协程

概念和Unity中的基本是类似的

但lua中的协程是一个特殊的线程(本质还是线程)

这点和Unity是不同的(Unity的协程不是线程)

一个可以暂停 恢复的线程 从而使得主线程不受阻塞的运行

--协程的创建
fun = function()
    print(123)
end

co = coroutine.create(fun)
--协程的本质是一个线程对象

co2 = coroutine.wrap(fun)
--这里的类型不是线程 而是函数

--协程的运行
coroutine.resume(co) --对应create创建的协程
co2() --对应wrap创建的协程

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

co3 = coroutine.create(fun2)
coroutine.resume(co3)
--挂起后要再次调用 否则只会执行一次

--resume有多个返回值
--第一个返回值代表协程是否启动成功
--之后是yield里面的返回值

--而通过wrap开启的协程 
--会把yield的返回值直接返回出来 

--协程的状态
coroutine.status(协程对象)
--有三种状态
--dead 死亡
--suspended 暂停
--running 执行中

print(coroutine.status(co3)) --suspended
print(coroutine.status(co)) --dead 因为没有挂起 所以判断为死亡了

--这个函数可以得到当前正在运行的协程的线程编号
coroutine.running()

特殊用法

多变量赋值

a,b,c = 1,2,"123"

a,b,c = 1,2
--1 2 nil
--多变量赋值 如果值不够会自动补空

a,b,c = 1,2,3,4,5,6
--多的值会忽略

多返回值

function Test()
    return 1,2,3,4
end
--多返回值 有几个变量接就接几个
--多了补空 少了忽略
a,b,c = Test()

三目运算符的实现

知识回顾 短路现象

检测到符合条件后 逻辑运算符后的内容不会执行

只在必要时才对后面的操作进行求值 被称为“短路求值”原则

lua不支持三目运算符 但是可以通过and or做到类似的效果

x = 3
y = 2
local res = (x>y) and x or y
print(res)

如果and成立了 那么or y这部分因为短路自然不会执行

反之 如果and不成立 那么就会执行y

所以就实现了三目的效果


元表

任何表变量都可以作为另一个表变量的元表

任何表变量都可以有自己的元表(父)

当我们子表中进行一些特定操作时

会执行元表中的内容

--设置元表
meta = {}
myTable = {}
--第一个参数 子表 第二个参数 元表
setmetatable(myTable,meta)

__tostring
meta2 = {
    __tostring = function(t)
    return t.name
    end
}
myTable2 = {
    name = "123"
}
setmetatable(myTable2, meta2)
print(myTable2)
--输出123
--当子表要被当做字符串使用时 会默认调用这个元表中的tostring方法
--相当于重写了字符串的方法

__call
meta3 = {
    __call = function(a)
        print(a)
        print("456")
    end
}
myTable3 = {
    name = "123"
}
setmetatable(myTable3, meta3)
--当子表 被当作一个函数来使用时 会默认调用这个call中的内容
myTable3()
--会输出
--123
--456

--运算符重载
meta4 = {
    --相当于运算符重载 子表使用+运算符时会调用
    __add = function(t1,t2)
        return t1.age + t2.age
    end
}

myTable4 = {age = 1}
setmetatable(myTable4, meta4)
myTable5 = {age = 2}

print(myTable4 + myTable5)

--其它可重载的
__sub减
__mul乘
__div除
__mod取余
__pow幂运算
__eq ==
__lt <
__le <=
--重载了小于就相当于重载了大于
__concat 拼接

--如果要用条件运算符 来比较两个对象
--这两个对象的元表一定要一致 才能准确调用方法

--__index 和_ _newindex
meta6 = {
    age = 1
}
meta6.__index = meta6
--也可以把赋值写到外面meta6.__index = {age = 2}
--但是__index的赋值得写在表外面

myTable6 = {}
setmetatable(myTable6, meta6)

print(myTable6.age)
--__index 当子表中 找不到某一个属性时
--会到元表中 __index指定的表去找索引

--__index可以一层一层嵌套

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

--其它
--得到元表的方法
getmetatable(myTable)
--找自己身上有没有这个变量 不考虑元表 如果没有就返回nil
rawget(myTable, "age")
--绕开__newindex 只会改自己的变量
rawset(myTable, "age", 2)

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注