t = {} table.insert(t,100) table.insert(t,1000) table.insert(t,10000) table.insert(t,1,10) table.insert(t,2,50) print(table.remove(t)) --10000 print(table.remove(t,4)) --1000 for k,v in pairs(t) do print(v) --10 50 100 end
table.insert(操作的table [,位置=#t+1] ,值)
table.remove(操作的table[,位置=#t])
key1 = {"one"} key2 = {"two"} t = {} setmetatable(t,{__mode="kv"}) t[key1] = 10 key1 = nil t[key2] = 100 key2 = nil collectgarbage() --主动调用gc回收垃圾 for k,v in pairs(t) do print(k,v) end
t的key值是一些table,后面被赋值为nil了,表明其实这条数据是不需要的了,但是gc是不知道的,这些table的key被存在的table引用着。
所以使用弱引用,设置table的元表的元方法__mode(一个字符串),带有k表示key值为弱引用,带有v表示value是弱引用,反正出现弱引用的值被nil了,整个条目都会被移除。
function newObject(value) return function(action,v) if action == "get" then return value elseif action == "set" then value = v else error("invalid action") end end end d = newObject(0) print(d("get")) --0 d("set",100) print(d("get")) --100
value值应该就是那个非局部变量了,每个对象用到一个closure,比用一个table高效。
local function search(k,plist) for i=1,#plist do local v = plist[i][k] if v then return v end end end function createClass(...) local o = {} local parents = {...} setmetatable(o,{__index=function(t,k) local v = search(k,parents) t[k] = v return v end }) o.__index = o function o:new(p) p = p or {} setmetatable(p,o) return p end return o end Named = {} Named.a = 10 Tell = {} Tell.b = 50 Acc = createClass(Named,Tell) acc = Acc:new() print(acc.b)
多重继承的话就不能通过某一个类来创建新的类型了,需要通过第三方的方法来创建类,参数传入基类们,创建一个新的table,它的元方法为可以在基类们中搜索对应值的search方法,缓存基类方法到具体的table(缺点是运行时修改基类的方法不会向下传递了,优点是访问加快了),为新table(类)提供一个new方法来创建对象,就是设置新table类为新新table的元表的__index。
People = {name='Chicai'} function People:New(o,name) o = o or {} setmetatable(o,self) self.__index = self name = name or 'Chicai' self.name = name return o end function People:printName() print(self.name) end Boy = People:New({sex='boy'}) function Boy:printSex() print(self.sex) end me = Boy:New() me:printName() me:printSex()
Boy是People的一个对象(Boy的元表的__index方法是People),Boy有自己的属性sex和方法printSex
me是Boy的一个对象,Boy调用继承过来的New方法,但是self参数改为了Boy,也就是说me的元表的__index是Boy
当me调用方法,在me中找不到时,就会去Boy的__index(还是Boy)中找,Boy也找不到,就去People找,调用时,self为me了
People = {name='Chicai'} function People:New(o,name) o = o or {} setmetatable(o,self) self.__index = self name = name or 'Chicai' self.name = name return o end function People:printName() print(self.name) end me = People:New() me:printName()
声明类People,其实是个Table,New方法用来创建实例,创建一个新的table-o代表实例,设置新table的元表为self就是People类,设置元表的__index元方法为self也还是People类,这样很绕,但是想想o就可以访问People定义好的属性和方法了。
me是一个元表为People的table(对象),me访问方法printName时,发现me没有这个方法,就会去元表的__index里面找,找到People:printName并调用,但是self参数传入的是me,调用me.name,同样找不到,到元表中的_index中找。
Account = {b = 0} function Account.withdraw(self,v) self.b = self.b - v return self.b end function Account:Haha(v) self.b = self.b + v return self.b end a = Account; Account = nil; print(a.withdraw(a,1)) -- -1 print(a:withdraw(1)) -- -2 print(a.Haha(a,10)) --8 print(a:Haha(10)) --18
:只是一种语法,就是一个可以自动添加self参数的语法,声明方法使用:,默认参数带有self,调用使用:时,将把调用方传进来。
例子中可以看.操作的模式,其实就是:实际的真正意思,:只是可以省略不写仅此而已。
array = {} array.mt = {} function array.new(t) local data = {} for k,v in ipairs(t) do data[v] = true end setmetatable(data,array.mt) return data end array.mt.__le = function(a,b) --<= for k in pairs(a) do --a是b的子集 if not b[k] then return false end end return true end array.mt.__lt = function(a,b) --< return a<=b and not (b<=a) end array.mt.__eq = function(a,b) --== return a<=b and b<=a end a1 = array.new{"hello","world"} a2 = array.new{"love","hello","tttt"} a3 = array.new{"tttt","love","hello"} print(a1 >= a2) --false print(a2 <= a3) --true print(a2 == a3) --true print(a2 < a3) --false print(a1 < a2) --false
关系类的元方法的两个操作元素table需要有一致的元表
array = {} array.mt = {} function array.new(t) local data = {} for k,v in ipairs(t) do data[v] = true end setmetatable(data,array.mt) return data end array.mt.__add = function(a,b) local data = array.new{} for k in pairs(a) do data[k] = true end for k in pairs(b) do data[k] = true end return data end array.mt.__tostring = function(t) local l = {} for k in pairs(t) do l[#l+1] = k end return table.concat(l,", ") end a = array.new{"one","three","love"} b = array.new{"you","two","one"} c = {"hello","world"} print(a) --three,love,one print(a+b) --two,one,love,three,you print(a+c) --1,2,one,love,three print(c+a) --1,2,three,love,one
这些二元的操作符,会先从左操作数找table对应的元方法,如果找到就用它,如果没找到,就找右操作数table的元方法,找到了就用,如果都没有,那就报错了。
Window = {} Window.prototype = {x=0,y=0,width=100,height=100} Window.mt = {} function Window.New(x) setmetatable(x,Window.mt) return x end Window.mt.__index = function(t,k) return Window.prototype[k] end t = Window.New({}) print(t.width) Window.mt.__newindex = function(t,n,v) error("not exists "..n,2) end --t.ll = 2 会报错 Window.mt.__index = {width=888} print(t.width) --888 Window.mt.__newindex = {} t.ll = 2; print(t.ll) --nil print(Window.mt.__newindex.ll) --2
__index元方法,主要table访问不存在的元素的时候,就会调用该方法,可以用来做继承,返回一些默认的值,如果__index是一个table,会自动去这个table查找那个值并返回。
__newindex元方法,主要在table对一个不存在属性进行赋值时调用的方法,如果__newindex引用的是一个table,那么会将值添加到这个table中了。