lua中的元表和元方法

元表概念

Lua中,面向对象是用元表这种机制来实现的
元表(matatable)
Lua在创建新的table时不会创建元表,比如以下代码就可以演示:

local t = {1, 2}
print(getmetatable(t))     -- nil

设置元表和获取元表(getmetatable和setmetatable)
使用getmetatable来获取一个table或userdata类型变量的元表,当创建新的table变量时,使用getmetatable去获得元表,将返回nil;同理,我们也可以使用setmetatable去设置一个table或userdata类型变量的元表

local t = {}
print(getmetatable(t))     -->nil   创建新的table,还没有设置元表,故为nil

local t1 = {}
setmetatable(t, t1)  --设置元表
assert(getmetatable(t) == t1)

任何table都可以作为任何值得元表,而一组相关的table有可以共享一个通用的元表,此元表描述了它们共同的行为。一个table甚至可以作为它自己的元表,用于描述其特有的行为。总之,任何搭配形式都是合法的

Set = {}
local mt = {} -- 集合的元表

-- 根据参数列表中的值创建一个新的集合
function Set.new(l)
    local set = {}
     setmetatable(set, mt)  --每调用一次这个函数,就创建一个set,并设置元表mt
    for _, v in pairs(l) do set[v] = true end
     return set
end


-- 并集操作
function Set.union(a, b)
    local retSet = Set.new{} -- 此处相当于Set.new({})
    for v in pairs(a) do retSet[v] = true end
    for v in pairs(b) do retSet[v] = true end
    return retSet
end

所有由Set.new创建的集合都具有一个相同的元表,例如

local set1 = Set.new({10, 20, 30})
local set2 = Set.new({1, 2})
print(getmetatable(set1))
print(getmetatable(set2))
assert(getmetatable(set1) == getmetatable(set2))  --他们的元表都是一样的

最后,我们需要把元方法加入元表中,代码如下:

mt.__add = Set.union
local set1 = Set.new({10, 20, 30})
local set2 = Set.new({1, 2})
local set3 = set1 + set2
Set.print(set3)

保护元表
保护元表,用字段__metatable。当我们想要保护集合的元表,是用户既不能看也不能修改集合的元表,那么就需要使用__metatable字段了;当设置了该字段时,getmetatable就会返回这个字段的值,而setmetatable则会引发一个错误;如以下演示代码:

function Set.new(l)
    local set = {}
     setmetatable(set, mt)
    for _, v in pairs(l) do set[v] = true end
     mt.__metatable = "You cannot get the metatable" -- 设置完我的元表以后,不让其他人再设置
     return set
end

local tb = Set.new({1, 2})
print(tb)
print(getmetatable(tb))  --得到You cannot get the metatable
setmetatable(tb, {}) -- 这儿已经不能设置元表的了

__index元方法:
默认情况下,当我们访问一个table中不存在的字段时,得到的结果是nil。但是这种状况很容易被改变;Lua是按照以下的步骤决定是返回nil还是其它值得:

当访问一个table的字段时,如果table有这个字段,则直接返回对应的值;
当table没有这个字段,则会促使解释器去查找一个叫__index的元方法,接下来就就会调用对应的元方法,返回元方法返回的值;
如果没有这个元方法,那么就返回nil结果。

Student = {} -- 创建一个命名空间

-- 创建默认值表
Student.default = { name= "zhangsan", age = 18, id = 1101  }

Student.mt = {} -- 创建元表

-- 声明构造函数
function Student.new(o)
     setmetatable(o, Student.mt)  --设置元表
     return o
end

-- 定义__index元方法
Student.mt.__index = function (table, key)
     return student.default[key]
end

local s = Student.new(name = "lisi")
print(s.name)               -- >lisi 访问自身已经拥有的值
print(s.age)          -- >18 访问default表中的值
print(s.id)          -- >1101 访问default表中的值
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值