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元表的相关介绍,下一章我会准备详细记录下与 元表 配合使用的 元方法。如果以上内容有偏差的地方欢迎各位大佬留言指出。

相关推荐
加油吧zkf3 分钟前
AI大模型如何重塑软件开发流程?——结合目标检测的深度实践与代码示例
开发语言·图像处理·人工智能·python·yolo
ejinxian18 分钟前
PHP 超文本预处理器 发布 8.5 版本
开发语言·php
软件黑马王子1 小时前
C#系统学习第八章——字符串
开发语言·学习·c#
阿蒙Amon1 小时前
C#读写文件:多种方式详解
开发语言·数据库·c#
Da_秀1 小时前
软件工程中耦合度
开发语言·后端·架构·软件工程
Fireworkitte1 小时前
Java 中导出包含多个 Sheet 的 Excel 文件
java·开发语言·excel
运器1232 小时前
【一起来学AI大模型】算法核心:数组/哈希表/树/排序/动态规划(LeetCode精练)
开发语言·人工智能·python·算法·ai·散列表·ai编程
whoarethenext3 小时前
使用 C++ 实现 MFCC 特征提取与说话人识别系统
开发语言·c++·语音识别·mfcc
ITfeib3 小时前
Flutter
开发语言·javascript·flutter
想躺平的咸鱼干3 小时前
Volatile解决指令重排和单例模式
java·开发语言·单例模式·线程·并发编程