leevis.com icon indicating copy to clipboard operation
leevis.com copied to clipboard

lua 表与元表总结

Open vislee opened this issue 9 years ago • 0 comments

  • lua中每个值都可以具有元表。元表中的方法称为元方法,定义原始值的一些行为。
    • setmetatable(table,metatable): 对指定table设置元表(metatable)
    • getmetatable(table): 返回对象的元表(metatable)。

元方法

  • __index

    • 当访问一个table的字段时,如果table有这个字段,则直接返回对应的值;
    • 找不到该字段,则判断该表是否有元表,没有元表返回nil,有元表则继续;
    • 判断元表有没有__index方法,如果__index方法为nil,则返回nil;如果__index方法是一个表,则重复上述步骤;如果__index方法是一个函数,则返回该函数的返回值。
  • __newindex __newindex元方法与__index类似,__newindex用于更新table中的数据,而__index用于查询table中的数据

  • __tostring tostring会调用

  • __call table作为方法调用时会调用该元方法。


--[[lua表,
    找函数是找的该表的元表的__function,
    找变量是先找该表的变量,如果没有则再找该表的元表的__index,如果该index是table,则从该table里找对应的变量,如果该index是function,直接返回该function的值。

]]
local y = {}
function y.__tostring()
    return "i am y"
end
y.a = "yy-a"

local x = {}
setmetatable(x, y)
---0----
print(x)

----1----
y.__index = y
print(x.a)

-----2---
y.__index = function() return 300 end
print(x.a)

-----3---
x.a = "xx-a"
print(x.a)

结果


i am y
yy-a
300
xx-a

  • __mode 取值 'k v',表示表的key,val是弱引用。

local t1, t2 = {}, {}
local t3, t4 = {}, {}

local arr = setmetatable({}, {__mode = "v"}) --可以k或v或kv

arr[1] = t1
arr[2] = t2
arr[t3] = "t3"
arr[t4] = "t4"

t1 = nil
t3 = nil

collectgarbage()

for k, v in pairs(arr) do
    print(k, v)
end

输出

#__mode = "k"
$ luajit ./t_test.lua
1	table: 0x0002d220
2	table: 0x0002d248
table: 0x000273a8	t4

#__mode = "v"
luajit ./t_test.lua
2	table: 0x00027438
table: 0x00027460	t3
table: 0x0002d220	t4
  • __gc 垃圾回收时会调用该方法。lua5.1和luajit需要特殊支持。
function setmt__gc(t, mt)
    local prox = newproxy(true)
    getmetatable(prox).__gc = function() mt.__gc(t) end
    t[prox] = true  --关键,实际上是当t被回收时,prox也没有引用被回收。prox回收时会调用他元表的gc方法
    return setmetatable(t, mt)
end


local iscollected = false
function gctest(self)
    iscollected = true
    print("cleaning up:", self)
end

local test = setmt__gc({}, {__gc = gctest})
collectgarbage()
assert(not iscollected)

test = nil
collectgarbage()
assert(iscollected)

  • __gc 垃圾回收时调用。luajit和lua5.1需要特殊支持。

function setmt__gc(t, mt)
    local prox = newproxy(true)
    getmetatable(prox).__gc = function() mt.__gc(t) end
    --让t的生命周期关联到prox。当t被回收时,prox也没有引用被回收。prox被回收时调用他元表的gc。
    t[prox] = true
    return setmetatable(t, mt)
end


local iscollected = false
function gctest(self)
    iscollected = true
    print("cleaning up:", self)
end

local test = setmt__gc({}, {__gc = gctest})
collectgarbage()
assert(not iscollected)

test = nil
collectgarbage()
assert(iscollected)

vislee avatar Jul 14 '16 14:07 vislee