Lua学习之metatable and metamethods(一)

最新看了文档,学习了一下第13章Metatables and Metamethods。对于metatable 和 metamethods这两个单词,我看的中文文档里面没有翻译,google翻译是元表,元操作。本文中会涉及到个人对这个章节的一些理解,也是刚学如果有不正确的地方,希望各位大神指出。
一.metatable and metamethods
1.metatable. 元表,基表。在C++ 中,我们子类继承基类之后,我们可以使用基类的部分方法。相似的,在Lua中,我们把t1设置为t2的metatable,当我们对t2进行各种操作的时候,所使用的方法不是t2所具备的,比如执行操作O1,这是会去查找t2的metatable也就是t1是否具备O1这个操作方法,如果有则调用。
举一个简单的例子:

local t1 = {1, 2, 3}
local t2 = {4, 5, 6}

print(t1 + t2) -- attempt to perform arithmetic on local 't1'(a table value)

当我们尝试把两个表相加的时候,就出错了。这时候,我们为这两个表定义一个metatable mt:

mt = {}
setmetatable(t1,mt)
setmetatable(t2,mt)

并且为mt加一个__add域:

mt.__add = function (a,b)
    local result = {}
    if #a == #b then
        for i=1,#a do
            result[i] = a[i] + b[i]
        end
    else
        print("wrong parameter")    
    end
    return result
end

这时候我们执行: print(t1 + t2)就不会报错了。我们写个函数把相加的结果打印出来。下面是完整的代码及运行结果:
Lua学习之metatable and metamethods(一)_第1张图片

local t1 = {1, 2, 3}
local t2 = {4, 5, 6}

--print(t1 + t2) -- attempt to perform arithmetic on local 't1'(a table value)

mt = {}
setmetatable(t1,mt)
setmetatable(t2,mt)


mt.__add = function (a,b)
    local result = {}
    if #a == #b then
        for i=1,#a do
            result[i] = a[i] + b[i]
        end
    else
        print("wrong parameter")    
    end
    return result
end

function output (t)
    for i=1,#t do
        print(t[i])
    end
end

output(t1 + t2)

这里写图片描述
2.metamethods. 在上面个这个里例子中,metatable mt的__add域就是一个metamethod。
二.算数运算的metamethods
我们知道算数运算符有加,减,乘,除,负,幂,metatable有着对应的域名:
__add, __sub, __mul, __div, __unm, __pow。还可以定义其他的行为,比如__concat定义连接行为。文档上面举了一个很好的例子关于集合的,__add函数作为求解两个集合的并集,__mul定义为两个集合的交集,在次上面,我加了一个__sub用来求解补集。下面是完整的代码和运行结果:

Set = {}

function Set.new (t)
    local set = {}
    for _,l in ipairs(t) do
        set[l] = true
    end
    return set
end

function Set.union (a,b)
    if getmetatable(a) ~= Set.mt or getmetatable(b) ~= Set.mt then
        error("attempt to 'add' a set with a non-set value",2)
    end

    local res = Set.new{}
    for k in pairs(a) do
        res[k] = true 
    end
    for k in pairs(b) do
        res[k] = true
    end
    return res
end

function Set.intersection (a,b)
    local res = Set.new{}
    for k in pairs(a) do
        res[k] = b[k]
    end
    return res
end

function Set.compliment (a,b)
    local res = Set.new{}
    for k in pairs(a) do
        if not(b[k]) then
            res[k] = true
        end
    end
    return res
end 

function Set.tostring (set)
    local s = "{"
    local sep = ""
    for e in pairs(set) do
        s = s..sep..e
        sep = ", "
    end
    return s.."}"
end

function Set.print (s)
    print(Set.tostring(s))
end

Set.mt = {} -- metatable for sets

function Set.new(t)
    local set = {}
    setmetatable(set,Set.mt)
    for _,l in ipairs(t) do
        set[l] = true
    end
    return set
end

s1 = Set.new{10,20,30,50}
s2 = Set.new{30,1}

print(getmetatable(s1))
print(getmetatable(s2))

Set.mt.__add = Set.union
Set.mt.__mul = Set.intersection
Set.mt.__sub = Set.compliment

s3 = s1 + s2
s4 = Set.new{1,5,10,20,30,50,45,78}
Set.print(s3)           --  输出s1和s2的并集
Set.print(s3*s1)        --  输出s1和s3的交集
Set.print(s4-s1)        --  输出s1关于s4的补集

Lua学习之metatable and metamethods(一)_第2张图片
三.关系运算的Metamethods
metatables提供的关系运算的metamethods有三个,__eq(等于),__lt(小于),和__le(小于等于),这三个可以让我们定义。对于另外的三个没有metamethod。Lua中是这么处理的:a~=b <=> not(a==b); a>b <=> b < a; a>=b <=>b<=a。这个是比较好理解的,文档提供了一个巧妙地例子,它首先定义__le,然后再通过__le去定义__lt和__eq,非常的简洁。

Set.mt.__le = function (a,b)
    for k in pairs(a) do
        if not b[k] then
            return false
        end
    end
    return true
end

Set.mt.__lt = function (a,b)
    return a<=b and not(b<=a)
end

Set.mt.__eq = function (a,b)
    return a <=b and b <=a
end

s1 = Set.new{2,4}
s2 = Set.new{4,10,2}
print(s1 <= s2)
print(s1 < s2)
print(s1 >= s1)
print(s1 > s1)
print(s1 == s1*s2)

Lua学习之metatable and metamethods(一)_第3张图片

你可能感兴趣的:(Lua)