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

相关推荐
你怎么知道我是队长4 小时前
C语言---枚举变量
c语言·开发语言
李慕婉学姐5 小时前
【开题答辩过程】以《基于JAVA的校园即时配送系统的设计与实现》为例,不知道这个选题怎么做的,不知道这个选题怎么开题答辩的可以进来看看
java·开发语言·数据库
吃茄子的猫5 小时前
quecpython中&的具体含义和使用场景
开发语言·python
云栖梦泽5 小时前
易语言中小微企业Windows桌面端IoT监控与控制
开发语言
数据大魔方5 小时前
【期货量化实战】日内动量策略:顺势而为的短线交易法(Python源码)
开发语言·数据库·python·mysql·算法·github·程序员创富
Edward.W7 小时前
Python uv:新一代Python包管理工具,彻底改变开发体验
开发语言·python·uv
小熊officer7 小时前
Python字符串
开发语言·数据库·python
月疯7 小时前
各种信号的模拟(ECG信号、质谱图、EEG信号),方便U-net训练
开发语言·python
荒诞硬汉7 小时前
JavaBean相关补充
java·开发语言
提笔忘字的帝国7 小时前
【教程】macOS 如何完全卸载 Java 开发环境
java·开发语言·macos