Lua学习笔记 — Table与Metatable(超详细)

01、Table

table是lua 中唯一的数据结构;既可以表示 hashtable 也可表示为 array;配合元表可以定制表复杂的功能(如实现面对对象编程中的类以及相应继承的功能)

数组

arr1 = {1,2,"abc"}
-- table.insert(table, [pos,] value) table 是要插入元素的表,pos 是可选参数,表示要插入的位置,默认为表末尾,value 是要插入的元素。
table.insert(arr1,3,33) -- 插入数据
--  遍历数组 在 Lua 索引值是以 1 为起始
for index, value in ipairs(arr1) do
    io.write("index=",index," value=",value," ") -- 打印打印不换行
    -- 运行结果:index=1 value=1 index=2 value=2 index=3 value=33 index=4 value=abc
end
print()
arr2 ={
    {1,11,111,1111,11111},
    {2,22,222,2222}
}
-- table.remove(list [, pos]) list 表示要进行删除操作的表,pos 表示要删除的元素的位置。如果没有指定 pos 参数,则默认删除表中的最后一个元素。
table.remove(arr2[2],2)
-- 可以使用#获取数组长度  type(arr2)获取数据类型
print("arr2[1][2]",arr2[1][2],"arr2.length",#arr2,"arr2[2].length",#arr2[1],type(arr2))
 -- 运行结果:arr2[1][2]  11  arr2.length  2   arr2[2].length 2   table

hashTable

dict = {
    k1 = "v1",
    k2 = "10086",
    k3 = "v3"
}
-- table.insert(dict,3,666) bad argument #2 to 'insert' (position out of bounds) 置超出了表的长度范围 (table.insert 函数无法直接用于 Lua 中的字典(或称为键值对)。table.insert 函数用于操作数组形式的表,而不是字典)
table.insert(dict,1,666) 
dict["age"] = 18
dict[10] = "v4"

table.remove(dict,2) -- 不会删除,因为不存在索引为2的数据(table.remove不能根据key来删除value,需要自己写代码实现根据key删除value)
print(dict.k1,dict.k2,dict["age"],dict["k3"],dict.k4)
-- pairs函数会遍历表的所有键值对,并按照任意顺序返回键和对应的值
-- ipairs函数则用于遍历数组部分的表项。它只会遍历连续的整数键,并按照索引顺序返回索引和对应的值。
-- 这里不能用ipairs进行遍历
for index, value in pairs(dict) do
    io.write("key=",index," value=",value," ") 
end
print()
-- 获取 table 的长度的时候无论是使用 # 还是 table.getn 其都会在索引中断的地方停止计数,而导致无法正确取得 table 的长度。如果需要
print(#dict)

运行结果

v1      10086   18      v3      nil
key=1 value=666 key=10 value=v4 key=k2 value=10086 key=k1 value=v1 key=age value=18 key=k3 value=v3 
1

02、元表(Metatable)

在Lua中,每个table都可以关联一个metatable。metatable是一个普通的table,可以包含一些特殊的字段(也称为元方法),这些字段定义了对应操作的行为。通过设置metatable,我们可以对table对象进行元操作的重载,实现自定义的行为。

常用元方法

  • __index:当访问一个table中不存在的索引时触发。
  • __newindex:当给一个table中不存在的索引赋值时触发(赋值会失败)。
  • _gc :元表中用一个以字符串 " gc " 为索引的域,那么就标记了这个对象需要触发终结器;
  • __add、__sub、__mul、__div等:用于重载算术操作符的行为,比如加法、减法、乘法、除法等。
  • __eq、__lt、__le:用于重载比较操作符的行为,比如相等、小于、小于等于等。
  • __tostring:用于将table转换为字符串的元方法。
  • __call:当一个table被当作函数调用时触发,可以通过该元方法使table对象具备函数的行为。

Demo

local tab = {
    k1 = "v1",
    k2 = "10086",
    k3 = "v3"
}


local meTab = setmetatable(tab,{
    __index = function (t, key)
        print("_index tab.k1=",t.k1,"key=",key)
        return "not find key"
    end,
    __newindex = function (t, key, value)
        -- table.insert(t,key,value) 在这里调用insert方法也不会插入成功
        print("__newindex key=",key,"value=",value)
    end,
    __gc =  function ()
        print("++++++++gc+++++++++++")
    end
})

print(myTab["ss"])
myTab["sss"] = "vaa"
table.insert(myTab,1,"v11")
for key, value in pairs(myTab) do
    io.write("key=",key," value=",value," ") -- 打印打印不换行
end
print()

运行结构

_index tab.k1=  v1      key=    ss
not find key
__newindex key= sss     value=  vaa
__newindex key= 1       value=  v11
key=k2 value=10086 key=k1 value=v1 key=k3 value=v3  # 赋值与insert失败
++++++++gc+++++++++++

03、Demo基于Table实现队列

local Queue = {}

function Queue:init()
    local queueData = {data = {}, head = 1, tail = 0}
    -- 通过setmetatable(queueData, self) 将 queueData对象与 Queue 类关联起来,并设置元表,使 queueData对象可以调用Queue类中定义的方法。
    setmetatable(queueData, self) 
    -- self.__index = self 设置对象的元表中的 __index 元方法,将其指向自己。目的是,在对象访问属性或方法时,如果对象本身没有该属性或方法,就会去访问元表的 __index 中指定的对象,以实现属性和方法的继承。
    self.__index = self
    return queueData
end

function Queue:isEmpty()
    return self.head > self.tail
end

function Queue:push(value)
    self.tail = self.tail + 1
    self.data[self.tail] = value
end

function Queue:pop()
    if self:isEmpty() then
        return nil
    end
    local value = self.data[self.head]
    self.data[self.head] = nil
    self.head = self.head + 1
    return value
end

使用

local myQueue = Queue:init()
myQueue:push(1)
myQueue:push("abc")
myQueue:push({1,2,3})

print(myQueue:pop())  -- 1
print(myQueue:pop())  -- abc
print(myQueue:pop())  -- table: 0x55be51926b00

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
THE END
分享
二维码
< <上一篇
下一篇>>