用继承的思想理解lua元表(转)

众所周知,lua最最核心的数据结构是table,是一个key-value hash表,可以用t.key或t[key]来查询。当key值不存在时,一般的hash表返回空值,但lua的table在一定条件下会触发元方法,在设置的元表table里继续查找,如果查到了,则返回元表里的值而不是空值。

跟继承类似:

A继承B,A:XXX(),如果A中没有此方法,则继续在B中查找
设置A的元表是B,A.key,如果A中没有key,在一定条件下到B中查找

 

1. lua查找元素的过程

local mt = {a = "mt"}
mt.__index = mt
local t = setmetatable({}, mt)
print("---------> ", t.a)   ---> mt

t.a,在表t中查找"a",不存在,如果t设置了元表,并且元表设置了__index域,则在元表设置的__index域mt中继续查找,即返回mt。如果没有设置元表返回nil。如果元表没有设置__index域也返回nil。如果在mt没找到,继续在mt的元表中继续查找,以此类推

复制代码
local mt1 = {a = "mt1"}
mt1.__index = mt1
local mt2 = setmetatable({}, mt1)
mt2.__index = mt2
local mt = setmetatable({}, mt2)
print(mt.a, mt2.a, mt1.a)    ----> mt1 mt1 mt1
复制代码

 

2. lua实现类

lua中并没有类的概念,但根据元表的特性很容易实现一个类。即设置obj表的元表为class表。有很多不同的实现思路,以下是一个常用的模板:

复制代码
local class = {}
class.__index = class

function class.New(cls, name)
    local self = setmetatable({}, cls)
    self.name = name
    return self
end

function class:print()
    print("name = ", self.name)
end


local obj = class:New("abc")
obj:print()     ---> name = abc
复制代码

 

3.lua实现继承

利用元表的特性,设置子类的元表为父类,当在子类找不到时,在父类中继续查找。

复制代码
local base = {}
base.__index = base

function base.New(cls, name)
    local self = setmetatable({}, cls)
    self.name = name
    return self
end

function base:print()
    print("name = ", self.name)
end


local class = setmetatable({}, base)
class.__index = class

function class.New(cls, name, age)
    local self = base.New(cls, name)
    self.age = age
    return self
end

function class:print2()
    self:print()
    print("age = ", self.age)
end


local obj = class:New("abc", 10)
obj:print2()             ---> name = abc   age =10
复制代码

 

4. lua的元表和元方法

lua的元表和元方法自定义一系列的操作集合,除了查找元素__index域外,还有__newindex, __gc, __tostring, __add等操作,详见http://cloudwu.github.io/lua53doc/manual.html

复制代码
local mt = {
    __tostring = function(t)
        local s=""
        for _, v in ipairs(t) do
            s = s .. v .. ","
        end
        return s
    end,
    __add = function(t1, t2)
        local t = {}
        for i, v in ipairs(t1) do
            t[i] = v
        end
        for i, v in ipairs(t2) do
            t[i] = (t[i] or 0) + v
        end
        return t
    end,
}

local t = setmetatable({1,2,3,4,5}, mt)
print(t)      ---> 1,2,3,4,5

local t1 = setmetatable({1,2,3}, mt)
local t2 = setmetatable({10,20,30,40,50}, mt)
local t3 = setmetatable(t1+t2, mt)
print(t3)     ---> 11,22,33,40,50
复制代码

 

注:如果用rawget(t, key),rawset(t, key, value),是不会触发元方法的,只在t中操作

posted on 2022-02-28 13:42  &大飞  阅读(52)  评论(0编辑  收藏  举报

导航