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

相关推荐
咩咩觉主1 小时前
C# &Unity 唐老狮 No.7 模拟面试题
开发语言·unity·c#
大丈夫在世当日食一鲲1 小时前
Java中用到的设计模式
java·开发语言·设计模式
却道天凉_好个秋2 小时前
c++ 嵌入汇编的方式实现int型自增
开发语言·汇编·c++
33三 三like2 小时前
软件工程画图题
java·开发语言·软件工程
&岁月不待人&3 小时前
Kotlin和Java区别
java·开发语言·kotlin
gallonyin3 小时前
免root运行python保活守护进程supervisor
linux·开发语言·python
tyler-泰勒3 小时前
c++:迭代器的失效
开发语言·c++
白晨并不是很能熬夜3 小时前
【JVM】字节码指令集
java·开发语言·汇编·jvm·数据结构·后端·javac
IT、木易3 小时前
大白话解释 JavaScript 中的this关键字,它在不同场景下是如何取值的?
开发语言·javascript·ecmascript
*.✧屠苏隐遥(ノ◕ヮ◕)ノ*.✧3 小时前
C语言_数据结构总结7:顺序队列(循环队列)
c语言·开发语言·数据结构·算法·visualstudio·visual studio