lua与c#交互内容总结

大纲如下
在这里插入图片描述

0x01 table

1. 基本原理

Lua 中的表(table)其实是一个"关联数组"(associative arrays),数组的索引可以是数字、字符串或表类型。在 Lua 里,table 的创建是通过"构造表达式"来完成,最简单构造表达式是{},用来创建一个空表。
table 是 Lua 的一种数据结构用来帮助我们创建不同的数据类型,如:数组、字典等。
Lua table 使用关联型数组,你可以用任意类型的值来作数组的索引,但这个值不能是 nil。
Lua table 是不固定大小的,你可以根据自己需要进行扩容。
当我们为 table a 并设置元素,然后将 a 赋值给 b,则 a 与 b 都指向同一个内存。如果 a 设置为 nil ,则 b 同样能访问 table 的元素。如果没有指定的变量指向a,Lua的垃圾回收机制会清理相对应的内存。

2. 获取长度及非空判断

一元运算符 返回一个字符串或者一个表的长度;
这里表示在表tags最后,插入元素4,因此表tags元素个数将会为4。在lua中“#”表示返回表长度,类似c+中的getlen()函数,不过,对于“#”操作,有几点需要注意:
1. 只有当键值是连续的数值键值时,返回值才是有意义的。
例如 local t = {“a”, “b”},这里table t的键值是1, 2,因此#t返回值为2
如果,table t这样定义 local t = { a = “a”, b = “b”},其键值分别为”a”、”b”,不是数值,因此#t放回为0,这个值其实没有任何意义,在不同平台上,可能返回数值不一样。
  2. 当table中,存在nil时,#返回的数值也是无意义。
这里网上有些资料是说,遇到nil时,会自动停止计算table长度,其实是不对的,可以看下面2个例子:

           local t = {“a”, nil, “b”}; 
           local t1 = {}; 
           t1[1] = “a”; 
           t1[2] = nil; 
           t1[3] = “b”; 
           print(#t); —- 返回3 
           print(#t1); —- 返回1 
     这里,可以看出一些猫腻。 综上两点,只有当table的键值是连续数值时,#返回值才是有意义的。如果在table中,存在非数值键值,或者nil时,其table并不是一个序列,因此#table并未定义,其返回值就是无意义,也就是说#table值可能在不同的平台上,返回值不一样。     

3. pairs和ipairs

pairs函数
  pairs()函数可以遍历table中的每一个元素;
  在for循环中,pairs()可以遍历整个table(即使不知道长度),并返回索引值和每一个元素的值;
  在遍历非数字索引的table时非常有用
ipairs函数

ipairs函数在遍历table时,遇到nil时,会跳出遍历。

0x02 元表

有两个很重要的函数来处理元表:
setmetatable(table,metatable): 对指定table设置元表(metatable),如果元表(metatable)中存在__metatable键值,setmetatable会失败 。
getmetatable(table): 返回对象的元表(metatable)。
以下实例演示了如何对指定的表设置元表:

            mytable = {}                          -- 普通表 
            mymetatable = {}                      -- 元表
            setmetatable(mytable,mymetatable)     -- 把 mymetatable 设为 mytable 的元表 
            以上代码也可以直接写成一行:
             mytable = setmetatable({},{})
            以下为返回对象元表:
             getmetatable(mytable)                 -- 这回返回mymetatable

1、元方法

    __newindex  元方法用来对表更新;
    __index  元方法用来对表访问;
    __call 元方法在 Lua 调用一个值时调用:
    __tostring 元方法用于修改表的输出行为;
 
    eg: 
      mytable = setmetatable({key1 = "value1"}, { __index = { key2 = "metatablevalue" } })
      print(mytable.key1,mytable.key2)

2、 总结

    Lua查找一个表元素时的规则,其实就是如下3个步骤:
    1.在表中查找,如果找到,返回该元素,找不到则继续;
    2.判断该表是否有元表,如果没有元表,返回nil,有元表则继续。
    3.判断元表有没有__index方法,如果__index方法为nil,则返回nil;如果__index方法是一个表,则重复1、2、3;如果__index方法是一个函数,则返回该函数的返回值。

0x03 lua与C#交互

1、C#调用Lua:C#先调用Lua的dll文件(C语言写的库),dll文件执行Lua代码

2、Lua调用C#:

1、Wrap方式:非反射机制,需要为源文件生成相应的wrap文件,当启动

Lua虚拟机时,Wrap文件将会被自动注册到Lua虚拟机中,之后,Lua文件

将能够识别和调用C#源文件。

总结:Lua调用Wrap文件, Wrap文件调用C#源文件

2、反射机制

0x04 lua与C#GC

1、lua GC

Lua 的 GC 是增量式 GC, 不会因为单次 GC 时间过长而 stop the world 造成主逻辑卡顿。Lua 5.2 中实验性的增加了分代 GC 特性, 可以通过接口在增量 GC 和分代 GC 之间切换. 分代 GC 的优点是可以快速回收短生命周期的临时对象, 缺点是周期性的强制全量 GC 可能引起卡顿;由于缺乏反馈, Lua 5.3 中又去掉了分代 GC。
在标记清除算法,引用计数算法,复制算法等常用的 GC 算法中, Lua 是使用的标记清除算法;
Lua 的所有对象引用都在虚拟机的准确管理下,因此可以准确的处理对象的引用情况(不是无法区别指针和数据的保守式GC);
链接: https://zhuanlan.zhihu.com/p/22403251.

2、C# GC

链接: https://www.cnblogs.com/zblade/p/11357203.html.

0x05 lua的面向对象

1、用元表和元方法

lua面向对象编程是基于元表metatable,元方法__index来实现的,通过元表的__index元方法,将一个table的__index元方法设置为另一个table,那么后者的方法就被前者继承。如果访问了lua表中不存在的元素时,就会触发lua的一套查找机制,也是凭借这个机制,才能够实现面向对象的。
总结元表的查找步骤:

步骤1.在表中查找,如果找到,返回该元素,找不到则继续步骤2
步骤2.判断该表是否有元表,如果没有元表,返回nil,有元表则继续步骤3
步骤3.判断元表有没有__index方法,如果__index方法为nil,则返回nil;如果__index方法是一个表,则重复步骤1、2、3;如果__index方法是一个函数,则调用该函数,并返回该函数的返回值。

元表像是一个备用查找表,假设表A的元表是B,那么在A中找不到的东西就会尝试在B中去找,设置元表的函数如下:
setmetatable(A, B),
这样表B就被设置为A的元表,当A中查找不到某个变量时就会到B中进行查找,元方法__index是用来确定一个表在被作为元表时的查找方法。

a、面向对象的封装

– 设置新对象的metatable
setmetatable(tempObj,Class)

b、面向对象的继承和多态

父类:-- 设置metatable的元方法__index,指向表Class自己
Class.__index = Class
– 设置新对象的metatable,
setmetatable(tempObj,Class)
子类:-- 设置元表为Class
setmetatable(SubClass, Class)
– 设置metatable的元方法__index,指向表SubClass自己
SubClass.__index = SubClass

2、直接将基类的成员深拷贝给子类

对外只有class函数,参数为基类的名称,返回一个派生类的对象数据。函数的作用是根据传入的基类,拿到对应的元表来初始化派生类对象的元表,这样在代码运行时,不需要动态向上查找,缺陷在于这样做在对象创建时会消耗更多的时间。
在这里插入图片描述
在这里插入图片描述

0x06深拷贝和浅拷贝

1、浅拷贝

在Lua中,使用赋值运算符"="进行浅拷贝的时候,分两种情况:

1、拷贝对象的类型是string、number、boolean这些基本类型的时候,会进行复制,创建一个新的对象,拷贝出来的对象和原来的对象互不影响,所以修改拷贝出来的对象的值不会影响到原来的对象的值!
2、拷贝对象的类型是table的时候,则是直接进行引用,拷贝出来的对象和原来的对象实际上是同一个对象,所以修改拷贝出来的对象中的元素的值也会使原来的对象中元素的值发生改变!

-- number
local numTest1 = 5
local numTest2 = numTest1  -- string、number、boolean这些基本类型使用"="会进行复制
numTest2 = 10  -- 修改numTest2的值,numTest1的值不会被修改
print(numTest1)
-- 5
 
-- string
local strTest1 = "hello world!"
local strTest2 = strTest1
strTest2 = "hello China!"
print(strTest1)
-- hello world!
 
-- table
local tblTest1 = {a = 1, b = 2, c = 3}
local tblTest2 = tblTest1  -- table使用"="进行的是引用
tblTest2.b = 99  -- 修改tblTest2中元素的值,tblTest1中对应元素的值也会被修改
print(tblTest1.b)
-- 99

2、深拷贝

那么问题来了:如果我现在想要table也实现深拷贝该如何操作呢?
Lua中是没有提供这样的api的,那就自己封装一个函数,递归拷贝table中所有元素以及设置元表即可!如下:

-- Lua table deep copy
function clone(object)
    local lookup_table = {}
    local function _copy(object)
        if type(object) ~= "table" then
            return object
        elseif lookup_table[object] then
            return lookup_table[object]
        end
        local new_table = {}
        lookup_table[object] = new_table
        for key, value in pairs(object) do
            new_table[_copy(key)] = _copy(value)
        end
        return setmetatable(new_table, getmetatable(object))
    end
    return _copy(object)
end
 
-- test
local deepCopyTest1 = {a = 1, b = 2, c = 3}
local deepCopyTest2 = clone(deepCopyTest1)
deepCopyTest2.b = 99
print(deepCopyTest1.b)
-- 

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值