lua重新学习笔记3(原表metatable以及元方法)

table中,可以重新定义的元方法有以下几个:

__add(a,b) 加法
__sub(a,b) 减法
__mul(a,b) 乘法
__div(a,b) 除法
__mod(a,b) 取模
__pow(a,b) 乘幂
__unm(a) 相反数
__concat(a,b) 连接
__len(a) 长度
__eq(a,b) 相等
__lt(a,b) 小于
__le(a,b) 小于等于
__index(a,b) 索引查询
__newindex(a,b,c) 索引更新
__call(a,...) 执行方法调用
__tostring(a) 字符串输出
__metatable 保护元表

Lua处理元表规则:

1.对于二元操作符,如果第一个操作数有元表,并且元表中有所需要的字段定义,那么Lua就以这个字段为元方法,而与第二个值无关。

2.对于二元操作符,如果第一个操作数有元表,但元表中没有需要的字段定义,那么Lua就去查找第二个操作数的元表。

3.如果两个操作数都没有元表,或者都没有对应的元方法定义,Lua就会引发一个错误

 

__tostring元方法

print(a) (a是一个table)

函数print总是调用tostring来进行格式化输出,当格式化任意值时,tostring会检查该值是否有一个__tostring的元方法

 

__metatable 保护集合的元表

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

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))
setmetatable(tb, {})

当设置后,getmetatable就会返回这个字段的值,而setmetatable则会引发一个错误

上述代码打印如下:

{1, 2}
You cannot get the metatable
lua: test.lua:56: cannot change a protected metatable

 

__index元方法

1.当访问一个table字段时,如果table有这个字段,则直接返回对应值,。

2.当table没有这个字段,则会促使解释器去查找一个__index的元方法,接下来就会调用对应的元方法,返回元方法返回值。

3.如果没有这个元方法,那么就返回nil结果

Windows = {} -- 创建一个命名空间
 
-- 创建默认值表
Windows.default = {x = 0, y = 0, width = 100, height = 100, color = {r = 255, g = 255, b = 255}}
 
Windows.mt = {} -- 创建元表
 
-- 声明构造函数
function Windows.new(o)
     setmetatable(o, Windows.mt)
     return o
end
 
-- 定义__index元方法
Windows.mt.__index = function (table, key)
     return Windows.default[key]
end
 
local win = Windows.new({x = 10, y = 10})
print(win.x)               -- >10 访问自身已经拥有的值
print(win.width)          -- >100 访问default表中的值
print(win.color.r)          -- >255 访问default表中的值

在实际编程中,__index元方法不必一定是一个函数,它还可以是一个table。当它是一个函数时,Lua以table和key作为参数来调用该函数,这就和上面的代码一样;当它是一个table时,Lua就以相同的方式来重新访问这个table,所以上面的代码也可以这样表示:

-- 定义__index元方法
Windows.mt.__index = Windows.default

具体应用(项目里面的物品表)

Config = Config or {}
Config.Goods = {
    [1] = {1, [[普通装备]]}
}

local Goods_Index = {
    goods_id = 1,
    goods_name = 2,
}

local mt_Goods = {
    __index = function(t,k)
        return rawget(t, Goods_Index[k])    
    end,
}

for k1, v1 in pairs(Config.Goods) do
    setmetatable(v1, mt_Goods)
end

print(Config.Goods[1].goods_name) -->普通装备

rawget(tb,i)对table tb进行一次“原始(raw)”访问,不会访问其元表。

 

__newindex元方法

__newindex用于更新table中的数据,而__index用于查询table中的数据,当对一个table中不存在的索引值赋值时,

1.Lua解释器先判断这个table是否有元表

2.如果有了元表,就查找元表中是否有__newindex元方法;如果没有元表,就直接添加这个索引,然后对应的赋值。

3.如果有这个__newindex元方法,Lua解释器就会执行它,而不是执行赋值。

4.如果这个__newindex对应的不是一个函数,而是一个table时,Lua解释器就在table中执行赋值,而不是对原来的table。

 

rawset(t,k,v),可以不涉及任何元方法而直接设置table t与key k相关联的value v。

 

你可能感兴趣的:(lua笔记)