哈喽,好久没有做记录了,最近刚好有时间打算整理一些基础常用内容,先做一期关于Lua相关的内容热热身。如果内容有误,欢迎大家指出我会积极做出响应。
在Lua中,元表(metatable) 和 元方法(metamethod) 是一对密切相关的概念,用于扩展表的行为。元表是一个特殊的表,用来定义元方法,而元方法则是元表中的某些特定字段,用于自定义表的操作行为,这一章主要记录元表(metatable)。
1. 什么是Lua
- 在开始介绍元表之前,我们先大致了解Lua是什么。
- Lua 是一种可嵌入、轻量、快速、功能强大的脚本语言。
- Lua 很适合用于配置、脚本化、插件化和快速构造原型的场景。
- Lua 是一门轻量级脚本语言,其核心设计目标之一是简单而高效。
- Lua 体积小、启动速度快,在所有脚本引擎中,Lua 的速可以于说是最快的。
- Lua 运行依托于宿主语言可以是c++,c#,golang等,只需要实现Lua解释器。
2. Lua的元表
Lua中设计 元表 的主要原因是为了提供一种灵活的机制。
元表 像是一个“操作指南”,里面包含了一系列的解决方案。
- 元表 能够扩展表的行为,而无需改变Lua本身的简单性和动态性。
- 元表 是 Lua 中的普通表,可以附加到另一个表上,用于改变该表的行为。
- 元表 赋予了Lua用户自定义操作的能力,如重载操作符,拦截访问,模拟面向对象编程等。
例如,当对一个表执行特定操作(如算术运算、比较操作或访问不存在的键)时,Lua 会检查是否有 元表 以及是否定义了对应的 元方法。
2.1 设置元表
通过 setmetatable 和 getmetatable 可以设置和获取表的元表。
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。 
print("表的初始值", getmetatable({}))           --> 表的初始值	nilprint("整型的初始值", getmetatable(10))         --> 整型的初始值	nil
print("浮点型的初始值", getmetatable(10.0))      --> 浮点型的初始值	nil--- 通过打印可以看到两个字符串的元表是同一个
print("字符串的初始值", getmetatable("新年快乐"))   --> 字符串的初始值	table: 0x600000b14640
print("字符串的初始值", getmetatable("Happy New Year"))  --> 字符串的初始值	table: 0x600000b14640print("布尔型的初始值", getmetatable(true))     --> 布尔型的初始值	nilprint("nil的初始值", getmetatable(nil))         --> nil的初始值	nilfunction sayHello()  end
print("函数的初始值", getmetatable(sayHello))   --> 函数的初始值	nil2.3 setmetatable
-  为表设置一个元表。元表是一个特殊的表,可以用来扩展和改变 Lua 表的行为。 
-  参数: -  table:需要设置元表的目标表。 
-  matetable:元表,要设置的元表,可以包含元方法(如 __index、__add等)。
 
-  
-  返回值:返回被设置元表的表,也就是参数table。 
-  给表设置元表 
local t = {}  -- 原始表
local mt = {} -- 元表setmetatable(t, mt) -- 设置元表
print(getmetatable(t) == mt) -- 输出 true
-  设置操作符重载 -  通过设置元表中的元方法,扩展表的行为。 
 
-  
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元方法,来实现默认值或继承。
 
-  
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字段,则返回该字段的值,而不是元表本身。
 
-  
-  获取表的元表 
local t = {}
local mt = {}setmetatable(t, mt)local retrieved = getmetatable(t)
print(retrieved == mt) -- 输出 true
-  保护元表 -   通过在元表中设置 __metatable字段,可以防止外部获取或修改元表。
 
-   
local t = {}
local mt = {}
setmetatable(t, mt)mt.__metatable = "Protected"print(getmetatable(t)) -- 输出 "Protected"-- 尝试修改元表会报错
-- setmetatable(t, nil) -- 报错:cannot change protected metatable
2.5 setmetatable 与 getmetatable 的关系
 
 
-  setmetatable用于设置元表。
-  getmetatable用于获取元表。
-  两者通常一起使用,用于实现自定义行为。例如: 
local t = {}
local mt = {__index = function(_, key)return "default value for " .. keyend
}setmetatable(t, mt)
print(getmetatable(t)) -- 输出元表 mtprint(t.foo) -- 输出 "default value for foo"
以上基本就是Lua元表的相关介绍,下一章我会准备详细记录下与 元表 配合使用的 元方法。如果以上内容有偏差的地方欢迎各位大佬留言指出。