读一读

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中了。