元表是Lua中最强大的特性之一,本节将深入讲解元表的工作原理、常用元方法、以及如何在Android开发中利用元表实现高级功能。
-- 创建普通表
local t = {x = 10, y = 20}
-- 创建元表
local mt = {
__index = function(t, k)
return "字段 "..k.." 不存在"
end
}
-- 设置元表
setmetatable(t, mt)
print(t.z) -- 输出"字段 z 不存在"
-- 获取已设置的元表
local meta = getmetatable(t)
if meta then
print("该表有元表")
end
-- 保护元表(禁止修改)
setmetatable(t, {
__metatable = "锁定的元表"
})
print(getmetatable(t)) -- 输出"锁定的元表"
setmetatable(t, {}) -- 会报错
local Vector = {}
Vector.__index = Vector
function Vector.new(x, y)
return setmetatable({x = x, y = y}, Vector)
end
-- 定义向量加法
function Vector.__add(a, b)
return Vector.new(a.x + b.x, a.y + b.y)
end
-- 使用示例
local v1 = Vector.new(1, 2)
local v2 = Vector.new(3, 4)
local v3 = v1 + v2 -- 调用__add
print(v3.x, v3.y) -- 输出4 6
-- 定义向量相等比较
function Vector.__eq(a, b)
return a.x == b.x and a.y == b.y
end
-- 定义向量大小比较
function Vector.__lt(a, b)
return (a.x^2 + a.y^2) < (b.x^2 + b.y^2)
end
-- 使用示例
print(v1 == v2) -- false
print(v1 < v3) -- true
-- 创建只读表
function readOnly(t)
return setmetatable({}, {
__index = t,
__newindex = function()
error("该表是只读的", 2)
end
})
end
-- 使用示例
local config = readOnly{
version = "1.0",
theme = "dark"
}
print(config.version) -- 输出"1.0"
config.version = "2.0" -- 报错
-- 带默认值的表
function withDefault(default)
return setmetatable({}, {
__index = function() return default end
})
end
-- 使用示例
local scores = withDefault(60)
print(scores["Alice"]) -- 输出60
-- 使表可被调用
local logger = setmetatable({}, {
__call = function(self, msg)
print(os.date() .. " - " .. msg)
end
})
-- 像函数一样调用表
logger("系统启动") -- 输出"2023-11-20 10:00:00 - 系统启动"
-- 自定义表输出格式
function Vector.__tostring(self)
return string.format("Vector(%d, %d)", self.x, self.y)
end
-- 使用示例
print(v1) -- 输出"Vector(1, 2)"
-- 实现原型继承
function inherit(proto)
local inst = {}
setmetatable(inst, {
__index = proto,
__call = proto.__call
})
return inst
end
-- 使用示例
local parent = {name = "Parent"}
local child = inherit(parent)
print(child.name) -- 输出"Parent"
-- 链式调用
local chain = setmetatable({}, {
__index = function(self, key)
return function(...)
-- 执行操作
return self -- 返回自身实现链式
end
end
})
-- 使用示例
chain:move(10,20):rotate(45):scale(2)
-- 包装Android View
function wrapView(view)
return setmetatable({view = view}, {
__index = function(t, k)
-- 优先查找Lua方法
local method = rawget(t, k)
if method then return method end
-- 其次调用Java方法
return function(...)
return t.view[k](t.view, ...)
end
end
})
end
-- 使用示例
local button = wrapView(findViewById(R.id.button))
button:setText("Click me") -- 调用Java方法
元表使用建议:
-- 检查元方法
function dumpMeta(t)
local mt = getmetatable(t)
if mt then
for k, v in pairs(mt) do
print(k, type(v) == "function" and "function" or v)
end
end
end
注意事项:
__index
和__newindex
会相互影响__eq
和__lt
)