推荐答案
在 Lua 中,常用的 metamethod 包括:
__index: 当访问表中不存在的键时触发。__newindex: 当给表中不存在的键赋值时触发。__add: 定义表的加法操作。__sub: 定义表的减法操作。__mul: 定义表的乘法操作。__div: 定义表的除法操作。__mod: 定义表的取模操作。__pow: 定义表的幂运算操作。__unm: 定义表的取负操作。__concat: 定义表的连接操作。__eq: 定义表的相等比较操作。__lt: 定义表的小于比较操作。__le: 定义表的小于等于比较操作。__call: 当表被当作函数调用时触发。__tostring: 当表被转换为字符串时触发。__metatable: 用于保护元表,防止被修改。
本题详细解读
1. __index 和 __newindex
__index 和 __newindex 是 Lua 中最常用的 metamethod 之一。__index 用于处理表中不存在的键的访问,而 __newindex 用于处理表中不存在的键的赋值操作。这两个 metamethod 通常用于实现继承、默认值等功能。
// www.javascriptcn.com code example
local t = {}
local mt = {
__index = function(table, key)
return "Default Value"
end,
__newindex = function(table, key, value)
rawset(table, key, value * 2)
end
}
setmetatable(t, mt)
print(t["nonexistent_key"]) -- 输出: Default Value
t["new_key"] = 10
print(t["new_key"]) -- 输出: 202. 算术操作的 metamethod
Lua 允许通过 metamethod 来定义表的算术操作。例如,__add 用于定义加法操作,__sub 用于定义减法操作,等等。
// www.javascriptcn.com code example
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 result = t1 + t2
print(result.value) -- 输出: 303. 比较操作的 metamethod
Lua 中的比较操作也可以通过 metamethod 来定义。__eq 用于定义相等比较,__lt 用于定义小于比较,__le 用于定义小于等于比较。
// www.javascriptcn.com code example
local t1 = { value = 10 }
local t2 = { value = 20 }
local mt = {
__lt = function(a, b)
return a.value < b.value
end
}
setmetatable(t1, mt)
setmetatable(t2, mt)
print(t1 < t2) -- 输出: true4. __call 和 __tostring
__call 允许表被当作函数调用,而 __tostring 允许表被转换为字符串。
// www.javascriptcn.com code example
local t = {}
local mt = {
__call = function(table, arg)
print("Called with argument: " .. arg)
end,
__tostring = function(table)
return "This is a table"
end
}
setmetatable(t, mt)
t("Hello") -- 输出: Called with argument: Hello
print(t) -- 输出: This is a table5. __metatable
__metatable 用于保护元表,防止其被修改。一旦设置了 __metatable,尝试获取或设置元表时,将返回 __metatable 的值。
// www.javascriptcn.com code example
local t = {}
local mt = {
__metatable = "Protected Metatable"
}
setmetatable(t, mt)
print(getmetatable(t)) -- 输出: Protected Metatable
setmetatable(t, {}) -- 报错: cannot change a protected metatable