Lua

lua优化经验总结

请尊重原作者的工作,转载时请务必注明转载自:www.xionggf.com 这是我在做一些手游项目时的lua优化经验总结。 注意清空table操作的效率问题 在Lua中,通常要清空一个table,很常见的方法就是直接赋值一个新的空table给指向table的变量:例如: local t = {“I am a table”} t = {} –- 现在t指向的table就是一个空的新建的table了。 这样子虽然逻辑上没什么问题,但t原来指向的那个table实质上就是一个“野table”了,它的何时被清理掉依赖于lua的gc操作。如果t本身就是存储着一些原生数字类型的数组的话,这种={}的清空操作是比较低效的。如果在每帧每秒都被调用的函数中,清空一个既有的table,可以采用以下的代码: -- [[这样子才是全部清空一个table中的所有项,如果将pairs函数改用ipairs函数则只会清空数组项,而不清空hash项]] for i, _ in pairs(t) do -- 不需要kv对中的value值,所以用哑元_代替 t[i] = nil end 利用逻辑判断的短路判定特性优化代码 对于逻辑或(or)操作,只要有一个判断条件为true,则结果为true。逻辑与操作,只要有一个判断条件为false,结果即为false,根据这个特性,在多条件判断时,将获取条件耗费性能最大的函数,挪到最后,尽可能地减少计算。例如: 逻辑与(and)操作,只要有一个判断条件为false,结果即为false。所以对于全逻辑与的操作,在计算判断条件时,应该每计算一次就判断一次,只要有一个为false,就立即得到判定逻辑与计算最终结果为false: 字符串常见问题 和Java,C#,Python等语言类似,一个字符串(对象)对应着一个常量字符串,一旦该字符串声明完毕,其指向的字符串内容即不可更改,所以如果有以下的代码: local s1 = “I” local s2 = “ am” local s3 = “ Lua” local s = s1..s2..s3 在第一个连字符操作完成后,会生成一个匿名的常量字符串,尔后该匿名字符串再和s3进行拼接,再生成一个新的字符串赋值给变量s。也就是说,Lua中的所有字符串,都不会发生“in place”操作,一切会对本字符串的内容发生了修改的操作,必然会导致一个新的字符串的产生。如果是存在着较多的字符串连接操作的话,可以使用table来模拟C#的StringBuilder,如下: -- table.concat函数所处理的表中,表项值只接受字符串和数字 function concat_string(s1,s2,s3,s4,s5,s6) -- 如果预先知道了要拼接多少个字符串,在定义table时可以预先 -- 开好多少个空位而不是直接创建空表,这样子有利于性能提升 local t = {nil,nil,nil,nil,nil} t.name = “I am table t” -- table.

Cocos2d-x之lua核心编程(第二版)》示例代码注释详解 3

请尊重原作者的工作,转载时请务必注明转载自:www.xionggf.com ##用表模拟面向对象编程中的类和对象 1 用元表实现一个People类 People = {age = 18} --[[ 等同于这样的声明方式: function People.new(self) self就是People表本身 --]] function People:new() local p = {} -- 生成一个表p setmetatable(p, self) -- 表p的元表设置为表People self.__index = self --[[ 表People的__index值就是__People本身。前文说到,__index对应的值可以是 一个table也可以是一个table。现在以一个table作为__index的值 --]] return p end function People:growUp() self.age = self.age + 1 print(self.age) end -- 测试 p1 = People:new() --[[ p1:growUp()的调用等价于:p1.growUp(p1)。这个语句的执行可以分解为以下的一些步骤: 1 首先要拿到函数p1.growUp。从People:new函数中可以知道:p1就是People:new函数中的p,一开始就是一个空表, 但这个空表p的元表就是表People,且空表p的元表People表的__index方法就是它自己,这也就是说。虽然p表是一个空表, 但是当执行到p1.growUp时,会查找执行到People.growUp的函数去执行之。 2 得到了People.growUp函数之后执行值,这里p1:growUp()的调用方式是等价于People.growUp(p1)。在growUp函数内部 当执行到self.age = self.age+1语句时,一开始的p1表中没有age项目,但执行语句后,首先会从People表中复制一份age项到 p1表,然后再对p1自身的age项加1.所以输出19。p2也是遵循这个“复制一份age项到p2表”的操作,故而最后也是输出19 --]] p1:growUp() -- 输出19 p2 = People:new() p2:growUp() -- 输出19 ###2 在People类的基础上定义Man类

Cocos2d-x之lua核心编程(第二版)》示例代码注释详解 2

请尊重原作者的工作,转载时请务必注明转载自:www.xionggf.com ##元表的__index方法和__newindex方法 ###1 使用__index方法的代码: --[[ Lua中访问table的元素是先通过__index元方法来查找是否有这个函数,如果没有则返回nil。可以通过改变__index元方法,能够 改变检索之后的结果。__index的值可以直接是一个table,可以是一个function。如果是table则以该table作为索引进行查询, 如果是function,则以table和缺少的table的元素键值的key为参数、 --]] Window = {} Window.mt = {} Window.prototype = {x = 0, y = 0, width=100, height = 100} --[[ 参数1是table,参数2是key,这是固定的格式 --]] Window.mt.__index = function(table, key) return Window.prototype[key] end function Window.new(t) setmetatable(t, Window.mt) -- 设置某个表t的元表为Window.mt return t end -- 测试 t = {x = 10, y = 20} w = Window.new(t) --[[ 表w就是表t,并且t的元表就是Window.mt。本来表t是没有“height”这一个元素项,但因为t指定了元表为Window.mt。 而Window.mt又对元方法__index进行了改写,所以t.height就是Window.prototype.width。如果t本身已经有"height"的话 那么t.height就不是Window.prototype.width了。 --]] print(w.height) ###2 使用了__newindex方法的代码 Window = {} Window.

Cocos2d-x之lua核心编程(第二版)》示例代码注释详解 1

请尊重原作者的工作,转载时请务必注明转载自:www.xionggf.com ##用元表针对一个table实现+操作 Set = {} -- 首先声明一个名字为"Set"的表,这个Set表,将会作为一个“类”。我们称之为“Set类” Set.mt = {} --[[为了避免命名空间污染,在Set表内部定义一个名为“mt”;类型为表的元素项。这个mt表将作为“表征Set类 的实例对象的表”的元表--]] --[[ Set表内部定义一个名为new,类型为函数的元素项。这个函数用来生一个“表征Set类的实例对象的表”。 从实现功能来看。这个函数类似于C++,Java中的 --]] function Set.new(t) local set = {} -- 生成一个表set,这个set表就等价于Set类的一个对象实例 Set.mt.__add = Set.union -- 表Set.mt的元方法__add就是类Set的union方法 setmetatable(set, Set.mt) -- 指定表set的的元表为Set.mt for i, v in ipairs(t) do -- 遍历传进来的table类型的参数t的每一项元素,然后将t的每一项元素的实值, set[v] = true -- 作为set表的键值 end return set -- 返回表set,即返回Set类的一个对象实例 end -- 合并两个集合a和b并且形成一个新Set对象 function Set.union(a, b) local res = Set.new() -- k short for key for k in pairs(a) do -- 遍历参数a的每一个键值,从new方法可以看到,这个a的键值就是new方法的参数t的实值 res[k] = true end for k in pairs(b) do -- 遍历参数b的每一个键值,从new方法可以看到,这个b的键值就是new方法的参数t的实值 res[k] = true end return res -- 完成两个循环之后,res表中就已经含有a和b的所有键值了。等同于合并了两个集合 end -- 把某一个Set对象格式化成字符串并返回 function Set.