Lua元表

哈喽,好久没有做记录了,最近刚好有时间打算整理一些基础常用内容,先做一期关于Lua相关的内容热热身。如果内容有误,欢迎大家指出我会积极做出响应。

在Lua中,元表(metatable) 和 元方法(metamethod) 是一对密切相关的概念,用于扩展表的行为。元表是一个特殊的表,用来定义元方法,而元方法则是元表中的某些特定字段,用于自定义表的操作行为,这一章主要记录元表(metatable)。

1. 什么是Lua

  • 在开始介绍元表之前,我们先大致了解Lua是什么。
  1. Lua 是一种可嵌入、轻量、快速、功能强大的脚本语言。
  2. Lua 很适合用于配置、脚本化、插件化和快速构造原型的场景。
  3. Lua 是一门轻量级脚本语言,其核心设计目标之一是简单而高效。
  4. Lua 体积小、启动速度快,在所有脚本引擎中,Lua 的速可以于说是最快的。
  5. Lua 运行依托于宿主语言可以是c++,c#,golang等,只需要实现Lua解释器。

2. Lua的元表

Lua中设计 元表的主要原因是为了提供一种灵活的机制。

元表 像是一个"操作指南",里面包含了一系列的解决方案。

  • 元表 能够扩展表的行为,而无需改变Lua本身的简单性和动态性。
  • 元表 是 Lua 中的普通表,可以附加到另一个表上,用于改变该表的行为。
  • 元表 赋予了Lua用户自定义操作的能力,如重载操作符,拦截访问,模拟面向对象编程等。

例如,当对一个表执行特定操作(如算术运算、比较操作或访问不存在的键)时,Lua 会检查是否有 元表 以及是否定义了对应的 元方法

2.1 设置元表

通过 setmetatablegetmetatable 可以设置和获取表的元表。

Lua 复制代码
local t = {}           -- 普通表
local mt = {}          -- 元表
setmetatable(t, mt)    -- 将元表附加到表 t 上

print(getmetatable(t)) -- 输出元表 mt
  • 每个表可以有一个独立的元表。

  • 轻量灵活:元表是普通的表,但它的字段有特殊的意义(元方法)。

  • 动态行为扩展:元表提供了一种机制,可以在不改变表本身的情况下扩展表的行为。

2.2 原始元表

  • Lua中元表的设置只能针对table,其他类型都不能设置。

  • Lua只有string初始化了元表,而且是针对所有的字符串,其他的类型都为nil。

  • table的原始元表为nil,也就是没有设置元表,只能通过 setmetatable进行设置。

  • 多个table可以共享一个table作为元表,也可以使用自己作为自己的元表,它自身也是table。

Lua 复制代码
print("表的初始值", getmetatable({}))           --> 表的初始值	nil

print("整型的初始值", getmetatable(10))         --> 整型的初始值	nil
print("浮点型的初始值", getmetatable(10.0))      --> 浮点型的初始值	nil

--- 通过打印可以看到两个字符串的元表是同一个
print("字符串的初始值", getmetatable("新年快乐"))   --> 字符串的初始值	table: 0x600000b14640
print("字符串的初始值", getmetatable("Happy New Year"))  --> 字符串的初始值	table: 0x600000b14640

print("布尔型的初始值", getmetatable(true))     --> 布尔型的初始值	nil

print("nil的初始值", getmetatable(nil))         --> nil的初始值	nil

function sayHello()  end
print("函数的初始值", getmetatable(sayHello))   --> 函数的初始值	nil

2.3 setmetatable

  • 为表设置一个元表。元表是一个特殊的表,可以用来扩展和改变 Lua 表的行为。

  • 参数:

    • table:需要设置元表的目标表。

    • matetable:元表,要设置的元表,可以包含元方法(如 __index__add 等)。

  • 返回值:返回被设置元表的表,也就是参数table。

  • 给表设置元表

Lua 复制代码
local t = {}  -- 原始表
local mt = {} -- 元表

setmetatable(t, mt) -- 设置元表
print(getmetatable(t) == mt) -- 输出 true
  • 设置操作符重载

    • 通过设置元表中的元方法,扩展表的行为。
Lua 复制代码
local t1 = {value = 10}
local t2 = {value = 20}
local mt = {
    __add = function(a, b)
        return {value = a.value + b.value}
    end
}

setmetatable(t1, mt)
setmetatable(t2, mt)

local t3 = t1 + t2
print(t3.value) -- 输出 30
  • 结合 __index 实现继承

    • setmetatable 常用于为表设置 __index 元方法,来实现默认值或继承。
Lua 复制代码
local defaults = {name = "Default", age = 0}
local t = {}

local mt = {
    __index = defaults
}

setmetatable(t, mt)

print(t.name) -- 输出 "Default"
print(t.age)  -- 输出 0
  • 注意事项

    • 只能为表设置元表,如果为非表类型设置元表,将会报错。

    • 同一个表只能有一个元表,之后调用 setmetatable会覆盖之前的元表。

2.4 getmetatable

  • 获取表的元表。

  • 如果表没有元表,或元表中设置了保护(__metatable),则返回 nil 或保护值。

  • 参数:

    • table:需要获取元表的目标表。
  • 返回值:

    • 如果表有元表,返回元表。

    • 如果没有元表,返回 nil

    • 如果元表设置了 __metatable 字段,则返回该字段的值,而不是元表本身。

  • 获取表的元表

Lua 复制代码
local t = {}
local mt = {}

setmetatable(t, mt)

local retrieved = getmetatable(t)
print(retrieved == mt) -- 输出 true
  • 保护元表

    通过在元表中设置 __metatable 字段,可以防止外部获取或修改元表。

Lua 复制代码
local t = {}
local mt = {}
setmetatable(t, mt)

mt.__metatable = "Protected"

print(getmetatable(t)) -- 输出 "Protected"

-- 尝试修改元表会报错
-- setmetatable(t, nil) -- 报错:cannot change protected metatable

2.5 setmetatablegetmetatable 的关系

  • setmetatable 用于设置元表。

  • getmetatable 用于获取元表。

  • 两者通常一起使用,用于实现自定义行为。例如:

Lua 复制代码
local t = {}
local mt = {
    __index = function(_, key)
        return "default value for " .. key
    end
}

setmetatable(t, mt)
print(getmetatable(t)) -- 输出元表 mt

print(t.foo) -- 输出 "default value for foo"

以上基本就是Lua元表的相关介绍,下一章我会准备详细记录下与 元表 配合使用的 元方法。如果以上内容有偏差的地方欢迎各位大佬留言指出。

相关推荐
西猫雷婶2 小时前
python学opencv|读取图像(十九)使用cv2.rectangle()绘制矩形
开发语言·python·opencv
liuxin334455663 小时前
学籍管理系统:实现教育管理现代化
java·开发语言·前端·数据库·安全
码农W3 小时前
QT--静态插件、动态插件
开发语言·qt
ke_wu3 小时前
结构型设计模式
开发语言·设计模式·组合模式·简单工厂模式·工厂方法模式·抽象工厂模式·装饰器模式
code04号3 小时前
python脚本:批量提取excel数据
开发语言·python·excel
小王爱吃月亮糖3 小时前
C++的23种设计模式
开发语言·c++·qt·算法·设计模式·ecmascript
hakesashou4 小时前
python如何打乱list
开发语言·python
网络风云4 小时前
【魅力golang】之-反射
开发语言·后端·golang
Want5955 小时前
Java圣诞树
开发语言·python·信息可视化
运维小文5 小时前
python之打印、变量、格式化输出
开发语言·python·python基础·hello world