Lua元方法
这一章主要记录介绍 元表 和 元方法 和使用,如果对 元表 不熟悉的同学可以闪现Lua元表。
元方法 是元表中的某些字段,定义了表在特定操作下的行为。例如,当表进行加法运算时,Lua会检查元表中的__add字段,并使用它定义的行为。
1. 常见元方法
元方法 | 作用 |
---|---|
__index | 在表中访问不存在的键时触发。 |
__newindex | 在表中对不存在的键赋值时触发。 |
__add | 重载加法运算符 + ,如对两个表进行 + 时触发。 |
__sub | 重载减法运算符 - ,如对两个表进行 - 时触发。 |
__mul | 重载乘法运算符 * ,如对两个表进行 * 时触发。 |
__div | 重载除法运算符 / ,如对两个表进行 / 时触发。 |
__mod | 重载取模运算符 % ,如对两个表进行 % 时触发。 |
__pow | 重载幂运算符 ^ ,如对两个表进行 ^ 时触发。 |
__concat | 重载字符串连接运算符 .. ,如对两个表进行 .. 时触发。 |
__eq | 重载相等比较运算符 == ,如对两个表进行 == 时触发。 |
__lt | 重载小于比较运算符 < ,如对两个表进行 < 时触发。 |
__le | 重载小于等于比较运算符 <= ,如对两个表进行 <= 时触发。 |
__call | 将表当作函数调用时触发。 |
__tostring | 定义 tostring() 函数的输出行为。 |
__metatable | 设置元表的保护,外部无法获取或修改元表。 |
以上包含了所有的元方法,下面会针对每一个展开记录。
2. __index
-
功能:
-
在访问表中不存在的键时触发。
-
用于提供默认值,实现继承等。
-
-
参数:
-
table:原始表(正在访问的表)。
-
key:访问的键名。
-
-
返回值:返回键对应的值。
-
如果 __index 元方法是一个表,则从该表中查找键的值。
-
如果 __index 元方法是一个函数,则会调用该函数并返回结果。
-
示例:返回默认值
local t = {}
local mt = {
__index = function(table, key)
return "default value for " .. key
end
}
setmetatable(t, mt)
print(t.foo) -- 输出 "default value for foo"
-
示例:实现简单继承
local Parent = {name = "Parent"}
local Child = {}
setmetatable(Child, {__index = Parent})
print(Child.name) -- 输出 "Parent"
3. __newindex
-
功能:
-
在为表中不存在的键赋值时触发。
-
-
参数:
-
table:原始表(正在访问的表)。
-
key:赋值的键名。
-
value:赋值的值。
-
-
返回值:无返回值。
-
__newindex 元方法必须是一个函数,不能是表这是Lua的设计特点与 __index 明确区分。
-
在表中赋值键时,如果元表中定义了 __newindex ,会调用该元方法不会直接修改原始表。
-
示例:
local t = {}
local mt = {
__newindex = function(_, key, value)
print("Setting " .. key .. " = " .. value)
end
}
setmetatable(t, mt)
t.foo = "bar" -- 输出 "Setting foo = bar"
4. __add
-
功能:
-
定义 + 运算符的行为。
-
-
参数:
-
a:第一个操作数,可以是表、数字或其他 Lua 数据类型。
-
b:第二个操作数,可以是表、数字或其他 Lua 数据类型。
-
-
返回值:加法运算结果(类型任意)。
-
当尝试对两个表使用 + 运算符时,Lua会调用元表的 __add 方法。
-
示例:加法运算
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
5. __sub
-
功能:
-
定义 - 运算符的行为。
-
-
参数:
-
a:第一个操作数,可以是表、数字或其他 Lua 数据类型。
-
b:第二个操作数,可以是表、数字或其他 Lua 数据类型。
-
-
返回值:减法运算结果(类型任意)。
-
当尝试对两个表使用 - 运算符时,Lua会调用元表的 __sub 方法。
-
示例:减法运算
local t1 = {value = 10}
local t2 = {value = 5}
local mt = {
__sub = function(a, b)
return {value = a.value - b.value}
end
}
setmetatable(t1, mt)
setmetatable(t2, mt)
local t3 = t1 - t2
print(t3.value) -- 输出 5
6. __mul
-
功能:
-
定义 * 运算符的行为。
-
-
参数:
-
a:第一个操作数,可以是表、数字或其他 Lua 数据类型。
-
b:第二个操作数,可以是表、数字或其他 Lua 数据类型。
-
-
返回值:乘法运算结果(类型任意)。
-
当尝试对两个表使用 * 运算符时,Lua会调用元表的 __mul 方法。
-
示例:乘法运算
local t1 = {value = 4}
local t2 = {value = 5}
local mt = {
__mul = function(a, b)
return {value = a.value * b.value}
end
}
setmetatable(t1, mt)
setmetatable(t2, mt)
local t3 = t1 * t2
print(t3.value) -- 输出 20
7. __div
-
功能:
-
定义 / 运算符的行为。
-
-
参数:
-
a:第一个操作数,可以是表、数字或其他 Lua 数据类型。
-
b:第二个操作数,可以是表、数字或其他 Lua 数据类型。
-
-
返回值:除法运算结果(类型任意)。
-
当尝试对两个表使用 / 运算符时,Lua会调用元表的 __div 方法。
-
示例:除法运算
local t1 = {value = 10}
local t2 = {value = 2}
local mt = {
__div = function(a, b)
return {value = a.value / b.value}
end
}
setmetatable(t1, mt)
setmetatable(t2, mt)
local t3 = t1 / t2
print(t3.value) -- 输出 5
8. __mod
-
功能:
-
定义 % 运算符的行为。
-
-
参数:
-
a:第一个操作数,可以是表、数字或其他 Lua 数据类型。
-
b:第二个操作数,可以是表、数字或其他 Lua 数据类型。
-
-
返回值:取模运算结果(类型任意)。
-
当尝试对两个表使用 / 运算符时,Lua会调用元表的 __div 方法。
-
示例:取模运算
local t1 = {value = 10}
local t2 = {value = 3}
local mt = {
__mod = function(a, b)
return {value = a.value % b.value}
end
}
setmetatable(t1, mt)
setmetatable(t2, mt)
local t3 = t1 % t2
print(t3.value) -- 输出 1
9. __concat
-
功能:
-
定义 .. 运算符的行为。
-
-
参数:
-
a:第一个操作表。
-
b:第二个操作表。
-
-
返回值:连接结果。
-
当尝试对两个表使用 .. 运算符时,Lua会调用元表的 __concat 方法。
-
示例:
local t1 = {name = "Alice"}
local t2 = {name = "Bob"}
local mt = {
__concat = function(a, b)
return a.name .. " & " .. b.name
end
}
setmetatable(t1, mt)
setmetatable(t2, mt)
print(t1 .. t2) -- 输出 "Alice & Bob"
10. __call
-
功能:
-
定义表被当作函数调用时的行为。
-
-
参数:
-
调用时传入的参数。
-
-
返回值:调用结果。
-
当表是函数并被调用时,Lua会调用元表的 __call 方法。
-
示例:
local t = {}
local mt = {
__call = function(_, arg)
return "Called with argument: " .. arg
end
}
setmetatable(t, mt)
print(t("Hello")) -- 输出 "Called with argument: Hello"
11. __tostring
-
功能:
-
定义 tostring() 函数的输出行为。
-
-
参数:
-
table:原始表。
-
-
返回值:返回字符串表示。
-
当表被放在 tostring() 内使用时,Lua会调用元表的 __tostring 方法。
-
示例:
local t = {name = "Alice"}
local mt = {
__tostring = function(table)
return "Name: " .. table.name
end
}
setmetatable(t, mt)
print(tostring(t)) -- 输出 "Name: Alice"
12. __metatable
-
功能:
-
用于保护表元,防止外部访问或修改元表。
-
-
参数:
-
无参数。
-
-
返回值:如果设置了 __metatable 则返回保护值。
-
提供外部只读访问,防止元表被修改导致意外行为。
-
在复杂项目中,保护核心逻辑不被破坏。
-
示例:
local t = {}
local mt = {
__index = function(_, key)
return "Default value for " .. key
end,
__metatable = "Protected"
}
setmetatable(t, mt)
print(t.foo) -- 输出 "Default value for foo"
print(getmetatable(t)) -- 输出 "Protected"
-- 尝试修改元表
-- setmetatable(t, nil) -- 报错:cannot change protected metatable
12. 总结
元方法 | 功能 | 参数 | 返回值 |
---|---|---|---|
__index | 访问不存在的键 | table,key | 键的值 |
__newindex | 拦截不存在的键的赋值 | table,key,value | 无 |
__add | 重载加法运算符+ | a,b | 加法结果 |
__concat | 重载字符串连接运算符.. | a,b | 连接结果 |
__call | 定义表被调用时的行为 | ... | 调用结果 |
__tostring | 自定义表的字符串表示 | table | 字符串 |
__metatable | 保护元表 | 无 | 保护值或nil |
-
通过元方法,可以深度自定义Lua表的行为,从而实现更多高级的功能。