lua中的元表和元方法

来源:互联网 发布:手机推荐 知乎 编辑:程序博客网 时间:2024/04/27 21:21

元表概念

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,还没有设置元表,故为nillocal 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 setend-- 并集操作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 retSetend

所有由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 + set2Set.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 setendlocal tb = Set.new({1, 2})print(tb)print(getmetatable(tb))  --得到You cannot get the metatablesetmetatable(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 oend-- 定义__index元方法Student.mt.__index = function (table, key)     return student.default[key]endlocal s = Student.new(name = "lisi")print(s.name)               -- >lisi 访问自身已经拥有的值print(s.age)          -- >18 访问default表中的值print(s.id)          -- >1101 访问default表中的值
0 0
原创粉丝点击