Lua中table(表)和元表的区别和使用

区别:在 Lua table 中我们可以访问对应的 key 来得到 value 值,但是却无法对两个 table 进行操作(比如相加)。

元表(Metatable),可以关联table的行为,并且与元方法对应关联

文章目录


前言

注意:

table使用关联型数组,不能使用nil当作值,其他任意值都是可以的。

table表也是不限制大小的。

table索引从1开始。


提示:以下是本篇文章正文内容,下面案例可供参考

一、table(表)和元表是什么?

table:table 是 Lua 的一种数据结构用来帮助我们创建不同的数据类型,如:数组、字典等。

元表:对table进行操作,对两个表进行相加

二、使用步骤

1.创建table(表)

代码如下(示例):

-- 普通表
local t = { 1, 2, 3, 4, 5 }

--遍历表的键值对
for k,v in pairs(t) do
    print("custom table:---"..k,v)
end


--table中可以放任何类型的东西
t = {
  function() return 123 end,
  function() print("abc") end,
  function(a, b) return a + b end,
  function() print("hello world") end,
}
t[1]()
t[2]()
t[3](1, 2)
t[4]()

functionList = {
  function(a, b)
    return a * b
  end,
  function(a, b)
    return a - b
  end,
  function(a)
    return -a
  end

}
a, b = 1, 2
print(functionList[1](a, b))
print(functionList[2](a, b))
print(functionList[3](a))

2.使用表的元素

代码如下(示例):

local table = { 1, 2, 3, 4, 5 }
--获取元素
print(t[1], t[2], t[3], t[4], t[5])
--指定元素值
t[6] = 6
print(t[6])
-- 移除引用
table = nil

--table下标的定义
t = { 6, 7, 8, 9 }
--上面和下面的代码等价
t = {
  [1] = 6,
  [2] = 7,
  [3] = 8,
  [4] = 9,
}
--甚至你可以跳过某些下标
t = {
  [1] = 6,
  [3] = 7,
  [5] = 8,
  [7] = 9,
}
print(t[7])
--输出9
--在声明后赋予元素值也是可以的
t = {} --空的table
t[101] = 10
print(t[101])
--输出10


t = {
  [1] = 123,
  [13] = "abc",
  [666] = "666"
}

print("下标为1的元素:", t[1], type(t[1]))
print("下标为13的元素:", t[13], type(t[13]))
print("下标为666的元素:", t[666], type(t[666]))


--下标进阶
t = {
  ["apple"] = 10,
  banana = 12,
  pear = 6,
}
--使用["下标"] = 值
--和  下标 = 值
--都是正确写法
--当第二种方式有歧义时,应该用第一种方式

--可以用下面两种方式访问:
print(t["apple"])
--输出10
print(t.apple)
--输出10

print(t.banana)
print(t.pear)

--lua全局变量和table
--在Lua中,所有的全局变量全部被存放在了一个大table中,这个table名为:_G
n = 6
print(_G.n)

t = {
  [10] = 100,
  num = 12,
  abc = {
    [1] = "a",
    [2] = "b",
    [3] = "abcd",
    [4] = "e",
  },
  a = {
    b = {
      c = 789
    }
  }
}

print("t[10]可获得number类型数据100:", t[10], type(t[10]))
print("t.num可获得number类型数据12:", t.num, type(t.num))
print("t.abc[3]可获得string类型数据abcd:", t.abc[3], type(t.abc[3]))
print("t.a.b.c可获得number类型数据789:", t.a.b.c, type(t.a.b.c))

3.关联元表

有两个很重要的函数来处理元表:

setmetatable(table,metatable): 对指定 table 设置元表(metatable),如果元表(metatable)中存在 __metatable 键值,setmetatable 会失败。

getmetatable(table): 返回对象的元表(metatable)。

代码如下(示例):

-- 普通表
local t = { 1, 2, 3, 4, 5 }

for k,v in pairs(t) do
    print("custom table:---"..k,v)
end

-- 通过setmetatable函数设置元表
local mymetable = {}
local mytable = setmetatable(t, mymetable)--把 mymetatable 设为 t 的元表
--设置的时候可以写成一行
local mytable1 = setmetatable({}, {})

print(getmetatable(mytable)) -- 这会返回 t的地址值

4.元表的元方法

1、__index元方法

  • 可以是表或函数。
  • 表:在表中查找不存在的键。
  • 函数:处理不存在的键查找。

2、__newindex 元方法

  • 可以是表或函数。
  • 表:将新键值对写入该表。
  • 函数:处理对不存在键的赋值操作。

必须是函数的元方法如下:

3、算术运算元方法

  • __add__sub__mul__div__mod__pow__unm__idiv__band__bor__bxor__bnot__shl__shr
  • 这些元方法必须是函数,用于定义相应的算术运算。

4、关系运算元方法

  • __eq__lt__le
  • 这些元方法必须是函数,用于定义相应的比较运算。

5、长度和连接运算元方法

  • __len__concat
  • 必须是函数,用于定义长度和连接运算的行为。

6、调用运算元方法

  • __call
  • 必须是函数,用于定义对表进行函数调用的行为。

7、迭代器元方法

  • __pairs__ipairs
  • 必须是函数,用于定义自定义迭代行为。

代码如下(示例):

-- 普通表
local t = { 1, 2, 3, 4, 5 }

for k,v in pairs(t) do
    print("custom table:---"..k,v)
end

-- 通过setmetatable函数设置元表
local mymetable = {}
local mytable = setmetatable(t, mymetable)--把 mymetatable 设为 t 的元表
--设置的时候可以写成一行
local mytable1 = setmetatable({}, {})

print(getmetatable(mytable)) -- 这会返回 t的地址值

-- __index元方法使用
-- __index元方法可以使用表或者函数来查找值
--[[
当你通过键来访问 table 的时候,如果这个键没有值,
那么Lua就会寻找该table的metatable(假定有metatable)中的__index 键。
如果__index包含一个表格,Lua会在表格中查找相应的键
]]
local other = { 1, 2, 3 }
--作为表
local othertable = setmetatable({}, { __index = other })
print(othertable[1])
--结果是1

--作为函数
local mytable2 = setmetatable({key = "value1"}, { __index = function (mytable2,key)
    if key == "key1" then
        return "value2"
    else
        return "value3"
    end
    end
})

print(mytable2.key, mytable2.key1)
--结果是value1 value2

-- __newindex元方法使用
--[[处理对表中不存在的键进行赋值的情况,
当试图给表中不存在的键赋值时,Lua 会调用 __newindex 元方法而不是直接在表中创建新的键值对。
__newindex 元方法接受三个参数:1. table 2. key 3. value
]]


local fallback = {}
--作为表
local t = setmetatable({}, {__newindex = fallback})

t.a = 1  -- 这个键值对会被设置到 `fallback` 表中
print(t.a)  -- 输出 nil,因为 `t` 表中没有 `a` 键
print(fallback.a) -- 输出 1,因为 `a` 键被设置到了 `fallback` 表中

--作为函数
local t = setmetatable({}, {
  __newindex = function(table, key, value)
    print("Attempt to set " .. key .. " to " .. value)
    rawset(table, key, value)  -- 使用 rawset 直接在表中设置键值对,绕过元方法
  end
})

t.a = 1  -- 输出 "Attempt to set a to 1"
print(t.a) -- 输出 1


--__tostring 元方法
--用于在将表转换为字符串时提供自定义行为。
local t1 = setmetatable({}, {
  __tostring = function(table)
    return "This is a table"
  end
})

print(t1) -- 输出 "This is a table"


--__add 元方法
--用于定义两个表相加时的行为。

local t2 = {value = 10}
local t3 = {value = 20}
setmetatable(t2, {
  __add = function(a, b)
    return {value = a.value + b.value}
  end
})

local t4 = t2 + t3
print(t4.value) -- 输出 30


--__call 元方法
--用于在将表当作函数调用时提供自定义行为。

local t5 = setmetatable({}, {
  __call = function(table, arg)
    return "Called with argument: " .. arg
  end
})

print(t5("hello")) -- 输出 "Called with argument: hello"


--__len 元方法
--用于定义表长度的计算行为。

local t6 = {1, 2, 3, 4, 5}
setmetatable(t6, {
  __len = function(table)
    return #table * 2
  end
})

print(#t6) -- 输出 10


--__eq, __lt, __le 元方法
--用于定义相等性、小于和大于比较的逻辑。
local t7 = {value = 10}
local t8 = {value = 10}
setmetatable(t7, {
  __eq = function(a, b)
    return a.value == b.value
  end
})

print(t7 == t8) -- 输出 true


--__concat 元方法
--用于定义表的连接操作行为。
local t9 = {value = "hello"}
local t10 = {value = "world"}
setmetatable(t9, {
  __concat = function(a, b)
    return a.value .. " " .. b.value
  end
})

print(t9 .. t10) -- 输出 "hello world"

--__pairs 和 __ipairs 元方法
--用于自定义表的迭代行为。
local t11 = {1, 2, 3, key1 = "value1", key2 = "value2"}
setmetatable(t11, {
  __pairs = function(table)
    local keys = {}
    for k in next, table do
      table.insert(keys, k)
    end
    table.sort(keys)
    local i = 0
    return function()
      i = i + 1
      if keys[i] then
        return keys[i], table[keys[i]]
      end
    end
  end
})

for k, v in pairs(t11) do
  print(k, v)
end




--实现只读表
local readonly = {}
local mt = {
  __index = function(table, key)
    return readonly[key]
  end,
  __newindex = function(table, key, value)
    error("Attempt to modify a readonly table")
  end
}

local t12 = setmetatable({}, mt)
readonly.a = 1

print(t12.a)  -- 输出 1
t12.a = 2  -- 报错 "Attempt to modify a readonly table"

5.表的操作

代码如下(示例):

1、创建和初始化表

-- 创建一个空表
local myTable = {}

-- 初始化表时添加一些键值对
local person = {
  name = "John",
  age = 30,
  isEmployed = true
}

-- 数组(序列)
local fruits = { "apple", "banana", "cherry" }

2、访问和修改表的元素

-- 访问表中的元素
print(person.name)  -- 输出 "John"
print(fruits[1])    -- 输出 "apple"

-- 修改表中的元素
person.age = 31
fruits[2] = "blueberry"

print(person.age)   -- 输出 31
print(fruits[2])  -- 输出 "blueberry"

 3、插入和删除元素

-- 插入元素
table.insert(fruits, "date")  -- 在末尾插入 "date"
table.insert(fruits, 2, "elderberry")  -- 在索引 2 处插入 "elderberry"

-- 删除元素
table.remove(fruits)  -- 删除最后一个元素
table.remove(fruits, 2)  -- 删除索引 2 处的元素

--还有一些别的方法..不一一举例了

-- 打印表中的所有元素
for i, v in ipairs(fruits) do
    print(i, v)
end

 4、遍历表

-- 遍历数组
for i, v in ipairs(fruits) do
  print(i, v)
end

-- 遍历字典
for k, v in pairs(person) do
    print(k, v)
end

 5、元表和元方法

-- 创建一个简单的元表
local mt = {
  __index = function(table, key)
    return "Key not found"
  end
}

-- 创建一个表并设置元表
local myTable = setmetatable({}, mt)

print(myTable.someKey) -- 输出 "Key not found"

 6、合并表

local function mergeTables(t1, t2)
  for k, v in pairs(t2) do
    t1[k] = v
  end
end

local t1 = {a = 1, b = 2}
local t2 = {c = 3, d = 4}
mergeTables(t1, t2)

for k, v in pairs(t1) do
  print(k, v)
end

7、表的长度

local t = {1, 2, 3, 4, 5}
print(#t)  -- 输出 5

 8、多重索引

local matrix = {
  {1, 2, 3},
  {4, 5, 6},
  {7, 8, 9}
}

print(matrix[2][3])  -- 输出 6

 9、表的克隆

local function cloneTable(orig)
  local copy = {}
  for k, v in pairs(orig) do
    if type(v) == "table" then
      copy[k] = cloneTable(v)
    else
      copy[k] = v
    end
  end
  return copy
end

local t1 = {a = 1, b = {c = 2, d = 3}}
local t2 = cloneTable(t1)
t2.b.c = 10

print(t1.b.c)  -- 输出 2
print(t2.b.c) -- 输出 10

 10、表排序

local numbers = {5, 2, 9, 1, 7, 6}
table.sort(numbers)

for i, v in ipairs(numbers) do
  print(i, v)
end

 11、表的元方法

local t = {10, 20, 30}

-- 设置元表
setmetatable(t, {
  __add = function(a, b)
    local result = {}
    for i = 1, #a do
      result[i] = a[i] + b[i]
    end
    return result
  end
})

local t2 = {1, 2, 3}
local t3 = t + t2  -- 使用元方法

for i, v in ipairs(t3) do
  print(i, v)  -- 输出 11, 22, 33
end

 12、表的默认值

local mt = {
  __index = function(table, key)
    return 0  -- 默认值
  end
}

local t = setmetatable({}, mt)
print(t.someKey)  -- 输出 0


总结

在 Lua 中创建和操作表,包括初始化、访问、修改、插入、删除、遍历、合并、克隆、排序等操作。通过熟练掌握这些操作,你可以在 Lua 中高效地处理各种数据结构和任务。

  • 17
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值