lua 给userdata设置元表_提高Lua语言开发效率的简单方法

59602f340981bdb9737646ce60f5b0e6.png

概述

首先,lua是一门高效的(efficient)、轻量级(lightweight)的嵌入式脚本语言(embeddable scripting language),这是它的官方网站的标语。

其次,lua也是一门面向原型的编程语言(prototype-based language)。这一点其实很好理解,因为lua有元表(metatable)的概念和用法。

截止到目前(2019.01.28),lua官方推出的最新版本如下:

lua

可以看到到,源码+文档说明的压缩档案才不到300KB,代码总数在2w行上下,在Linux上可以编译成182KB左右的可执行文件,说明lua确实很小巧。

语法特性

这篇文章非常详细地总结了lua语言的优缺点,我这边稍微摘抄几个重点介绍下。

1、lua支持多个函数返回值,代码如下:

return 

2、lua支持列表项的展开与打包(pack与unpack),代码如下:

print 

这在做函数调用和参数传递时,会非常有用。

3、lua的数据类型,有如下几种:

(1)nil 空值

(2)boolean 布尔值,只有 true 和 false

(3)number 数字类型,用c语言的双精度浮点数(double)实现,lua 5.3+版本支持64位长整型。

(4)function 函数类型

(5)table lua表,内部由C语言的无序哈希表和C语言数组实现。

local 

(6)Thread lua协程,目前看来,lua并不支持多线程,只是在协同程序上实现了并发。这里有一篇文章详细地介绍了lua协程的用法和特点。

(7)LIGHTUSERDATA 一个 C 指针,由自己管理,lua不会回收。

(8)USERDATA 一块内存区域,由lua管理,自动回收。

(9)upvalue 非临时变量,一般用于lua的闭包

如何提升lua的开发效率

(一)类似面向对象的设计

lua本身不是面向对象编程语言,所以它没有继承、多态这些复杂的语法特性。但是,作为一个面向原型编程语言,lua提供了元表,在一定程度上,提供了类似面向对象的设计思路。

比如,我们可以设计一个ClassBase.lua,定义一个lua“基类”

ClassBase 

有了基类的方法,现在可以设计一个好友窗口类,它有自己的方法SortFriend,表示对好友进行排序,同时,它需要使用基类的方法,那么FriendWindow.lua代码如下:

FriendWindow 

对于lua表的属性访问,如果该表没有定义__index,则会去该lua表的元表的__index去寻找相应的属性,以此类推。

FriendWindow的元表的__index属性是ClassBase,这样我们可以通过FriendWindow间接使用ClassBase中的属性和方法。

这里很巧妙的,将FriendWindow的元表的__newIndex设置为一个空lua表,就是说,如果要在后续使用FriendWindow的过程中,要想写入一些新的属性和方法,则实际上,是写入到了这个空表中。好处就是,如果想直接清掉这些新属性和新方法的话,可直接修改__newIndex即可。这样的设计,可以极大程度地保留FriendWindow的固有结构,便于清空临时数据,这在游戏逻辑的数据管理中,非常重要。

同时,在FriendWindow的元表中,定义了__call,好处就是:

FriendWindow.key1 

(二)数据保护

有时,为了防止其他程序员擅自修改某些lua表中记录的数据,可以将这些数据做“只读化处理”,通过元表可以轻松实现这些特性。

local 

定义一个局部函数变量,lua内部会在内存中存储该函数的函数体,同时生成一个局部函数指针,指向函数体。 如果多次定义相同的函数,通过lua调试器可以发现,函数变量的指针地址,每一次都是不相同的。所以这里索性在代码初始的地方,就定义func_readonly这个函数,可以节约函数指针所消耗的内存空间。

通过调用GetReadOnlyValue()方法,获得某一个lua表的只读副本,从而保护lua表中的数据。这在使用配置表数据等应用场景中,非常好用。

lua虚拟机

诸如JVM、Python解释器,这类虚拟机是基于堆栈的虚拟机(stack based vm)。

关于lua虚拟机以及指令相关的内容,这篇文章讲得比较好,我这里做了简单的摘抄。

例如实现两个变量相加 (a = b + c),这类虚拟机通常会将代码编译成如下的指令:

PUSH 

而lua虚拟机,是基于寄存器的虚拟机(register based vm)。同样实现两个临时变量相加,虚拟机编译的代码会简单得多:

ADD  a  b  c   ; // a = b + c

其中,b、c是被加数和加数(均为操作数),结果存放于a。

Register based vm(基于寄存器的架构) 的指令可以直接对应标准的3地址指令,用一条指令完成了上面多条指令的计算工作,并且有效地减少了内存复制操作。

这样的指令系统对于效率有很大的帮助。

不过,在编译器设计上,就要在代码生成阶段对寄存器进行分配,增加了实现的复杂度。并且每条指令所占用的存储空间也相应的增加了。

对于lua来说,使用局部变量,和全局变量,lua代码编译后的字节码,是完全不一样的。

例如如下的代码,定义了两个临时变量a、b并进行求和操作:

local   

经过编译后的字节码如下:

ADD  0   0   1


未完待续。。。。。。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值