Lua语法(三)——元表与元方法

简介: Lua语法(三)——元表与元方法

简介

  在Lua中,元表(metatable)是一种特殊的表,用于控制其他表的行为。每个表可以关联一个元表,通过设置元表和元方法,可以修改表的一些默认行为。
  元方法(metamethod)是一种特殊的函数,用于定义表的一些特殊操作。
  元方法通过在元表中定义特定的字段来实现。例如,当表进行加法操作时,Lua会检查表的元表中是否定义了add字段。如果定义了add字段,Lua会调用该字段对应的函数来执行加法操作。

正文

元表

只有字符串才有默认的元表,其他类型需要手动添加

任何表都可以作为其他表的元表

---------1.初体验,设置元表,获取元表
t={
   }
t1={
   }        --元表
print(getmetatable(t))
setmetatable(t,t1)        --设置元表
print(getmetatable(t))
print(getmetatable("nihao"))
print(getmetatable("hello"))
print(getmetatable(10))
--输出
nil
table: 00000000006e9df0
table: 00000000006e9ef0
table: 00000000006e9ef0
nil

-----2.获取字符串默认的元表以及里面的元方法
tab = getmetatable("hello")
for index, value in pairs(tab) do
    print(index,value)    --元表
    for key, value in pairs(value) do
        print(key,value)    --所有元方法
    end
end
--输出
__index    table: 0000000000ea9f30
rep    function: 000000006849d270
format    function: 000000006849eb30
char    function: 000000006849d730
gsub    function: 000000006849fe90
upper    function: 000000006849d150
match    function: 000000006849fe70
unpack    function: 000000006849ddf0
reverse    function: 000000006849d1e0
lower    function: 000000006849d3d0
byte    function: 000000006849f4a0
dump    function: 000000006849f300
gmatch    function: 000000006849d680
sub    function: 000000006849f3a0
pack    function: 000000006849e150
packsize    function: 000000006849dcb0
find    function: 000000006849fe80
len    function: 000000006849cf10

元方法

表相关常用的元方法

__index

对应方法是索引符号。例如 a[10] 的 [ ]

如果查找表元素越界,那么就会调用这个元方法

local t = {
   "hello","ni","www"}
local metable={
   
    __index = function (tab,index)
        -- print(index)     --这里是输出越界的索引值
        if index>#tab then
            return "越界了"
        end
    end
}
setmetatable(t,metable)

print(t[3])
print(t[4])

--输出
www
越界了
__newindex

如果对表新增一个值,那么就会调用这个元方法

1.其中要想再这个元方法里面给表赋值,只能使用rawset方法

2.如果__newindex方法内不做任何操作,则此表变成只读表

---1.常规用法
---只读表
local t = {
   "hello","ni","www"}
local metable={
   
    __newindex =function (tab,index,value)
    end
}
---1.1添加值
local t = {
   "hello","ni","www"}
local metable={
   
    __newindex =function (tab,index,value)
        print("添加了一个新值",index,value)
        rawset(tab,index,value)    --注意这个方法
    end
}
setmetatable(t,metable)

print(t[3])
print(t[4])
t[4] = "aaaa"
print(t[4])
--输出
www
nil
添加了一个新值    4    aaaa
aaaa


---2.使用__newindex 控制添加的值
local myTable = {
   } -- 创建一个空表

local allowedTypes = {
   number = true, string = true} -- 只允许添加number和string类型的值
local allowedKeys = {
   foo = true, bar = true} -- 只允许添加键为foo和bar的值

-- 创建元表,并设置__newindex元方法
local metaTable = {
   
  __newindex = function(tbl, key, value)
    if not allowedTypes[type(value)] then -- 检查值的类型
      error("Only values of type number or string are allowed.") -- 抛出错误,拒绝添加
    end
    if not allowedKeys[key] then -- 检查键的合法性
      error("Only keys 'foo' and 'bar' are allowed.") -- 抛出错误,拒绝添加
    end
    rawset(tbl, key, value) -- 符合规则,允许添加
  end,
}

setmetatable(myTable, metaTable) -- 将元表设置给表

myTable.foo = 42 -- 允许添加
print(myTable.foo) -- 输出 42

myTable.baz = "test" -- 错误: 只允许键为foo和bar的值
print(myTable.baz) -- 不会输出任何值
__len

对应的是 #tab 取长度

local myTable = {
   10,5,1,0} -- 创建一个空表

local metaTable = {
   
     __len=function (tab)
        local i = 0
        for key, value in pairs(tab) do
            i=i+1
        end
        print("len is ",i)
        return i
    end
}

setmetatable(myTable, metaTable) -- 将元表设置给表

print(#myTable)
--输出
len is     4
4
__call

对应的是小括号符号。 例如 table(arg),这里的( )

local mytable={
   10,5,0}

local metable ={
   
    __call =function (tab,...)
        local str = "["
        str =str..table.concat({
   ...},",")
        str = str.."]"
        for key, value in pairs({
   ...}) do
            print(key,value)
        end
        return str
    end
}

setmetatable(mytable,metable)

print(mytable(99,15,16))
--输出
1    99
2    15
3    16
[99,15,16]

算术及关系运算 元方法

元方法 对应算术操作
__add 对应的运算符 '+'.
__sub 对应的运算符 '-'.
__mul 对应的运算符 '*'.
__div 对应的运算符 '/'.
__mod 对应的运算符 '%'.
__pow 对应的运算符 '^'幂指数
__unm 对应的运算符 '-'取反
__concat 对应的运算符 '..'连接
__eq 对应的运算符 '=='.
__lt 对应的运算符 '<'.
__le 对应的运算符 '<='.
__add
__eq
__len
__unm
综合案例
local myTable = {
   10,5,1,0} -- 创建一个空表

local metaTable = {
   
    __add=function (tab,newtab)
        local res ={
   }
        for i = 1, #tab do
            res[#res+1]=tab[i]
        end
        for i = 1, #newtab do
            res[#res+1] = newtab[i]
        end
        return res
    end,
    __eq=function (tab,newtab)
        if #tab ~= #newtab then
            return false
        end
        for i = 1, #tab do
            if tab[i]~=newtab[i] then
                print(tab[i],",",newtab[i])
                return false
            end
        end
        return true
    end,
    __len=function (tab)
        local i = 0
        for key, value in pairs(tab) do
            i=i+1
        end
        print("len is ",i)
        return i
    end,
    __unm =function (tab)
        local res ={
   }
        for i = 1, #tab do
            res[#res+1] = -tab[i]
        end
        return res
    end
}

setmetatable(myTable, metaTable) -- 将元表设置给表
--[[    --__len
print(#myTable)
--]]

--[[    --__add
local newtab={}
local res = newtab+myTable
for index, value in pairs(res) do
    print(index,value)
end
--]]

--[[    __eq
local newtab ={}
local res = newtab == myTable
print(res)
----------------------------
-- setmetatable(newtab,metaTable)
-- local emtab ={}
-- local re = emtab == newtab
-- print(re)
--]]


--[[ --__unm
print(myTable[1])
local ss=-myTable
print(ss[1])
--]]

库定义元方法

__tostring

比如在输出中自动转换为字符串形式就会调用这个

local mytable={
   10,5,1,0}

local metable={
   
    __tostring =function (tab)
        local res="["
        res = res .. table.concat(tab,",")
        res = res .. "]"
        return res
    end
}

setmetatable(mytable,metable)
print(mytable)
---------------------------------------
-- 这两个注释切换的时候要等2分钟才能有效
-- function ToStr(tab)
--     local res="["
--     res = res .. table.concat(tab,",")
--     res = res .. "]"
--     return res
-- end

-- local meta ={}
-- setmetatable(mytable,meta)
-- meta.__tostring = ToStr

-- print(mytable)
__pairs

当使用for循环使用 pairs 键值对 遍历表的时候调用该 元方法

-- 定义一个表和一个迭代器函数
local myTable = {
   10,5,0,1}
local function myPairs()
    local i = 0
    return function()
        i = i + 1
        if myTable[i] then
            return i, myTable[i]
        end
    end
end

-- 创建一个元表并设置__pairs字段
local metatable = {
   
    __pairs = function()
        return myPairs()
    end
}

-- 将元表设置为myTable的元表
setmetatable(myTable, metatable)

-- 使用pairs迭代myTable
for key, value in pairs(myTable) do
    print(key, value)
end

--输出
1    10
2    5
3    0
4    1
目录
相关文章
|
11月前
|
索引
lua元表、元方法
lua元表、元方法
72 0
|
2月前
|
Java API C语言
Lua语法(一)
Lua语法(一)
25 0
Lua语法(一)
|
2月前
Lua语法(六)——面相对象编程
Lua语法(六)——面相对象编程
29 0
|
2月前
|
Java
Lua语法(五)——垃圾回收
Lua语法(五)——垃圾回收
75 0
|
2月前
Lua语法(四)——协程
Lua语法(四)——协程
35 0
|
2月前
|
缓存
Lua语法(二)——闭包/日期和时间
Lua语法(二)——闭包/日期和时间
74 0
|
4月前
|
存储 缓存 NoSQL
Redis系列学习文章分享---第十三篇(Redis多级缓存--JVM进程缓存+Lua语法)
Redis系列学习文章分享---第十三篇(Redis多级缓存--JVM进程缓存+Lua语法)
78 1
|
5月前
|
NoSQL JavaScript Java
Lua开发环境搭建和基础语法
Lua开发环境搭建和基础语法
124 1
|
5月前
|
Java Kotlin 索引
Lua 起航 —— 一些常用基础语法
Lua 起航 —— 一些常用基础语法
66 1
|
5月前
|
Kubernetes NoSQL Java
Lua 元表及常见元方法
Lua 元表及常见元方法