【Lua特性】Metatable(元表)

__index 元方法

主要用于table的查询,其可为table或function.

table[key] 的访问过程,首先检查table表中是否存在key的字段,如果有则返回,否则检查是否有__index的元方法,没有返回nil,有则查找元方法。

__newindex 元方法

主要用于table的更新(赋值),其可为table或function.

a.如果__newindex是一个函数,则在给table不存在的字段赋值时,会调用这个函数。
           b.如果__newindex是一个table,则在给table不存在的字段赋值时,会直接给__newindex的table赋值。

local parent = {
    atk  = 1
}

local child = {
    hp = 2
}

parent.__index = parent

setmetatable(child, parent)

print(child.atk)  -- ot:1
print(child.hp)   -- ot:2


parent.__newindex = function ( t, k ,v )
	if k == "atk" then
		parent[k] = v * 2
	end
end

child.atk = 3
child.hp = 4

print(child.atk)  -- ot:6
print(child.hp)   -- ot:4

parent.__index = nil

print(child.atk)  -- ot:nil
print(child.hp)   -- ot:4

 

操作符

local v1 = { x = 1, y = 2 }
local v2 = { x = 3, y = 4 }

local meta = {}

meta.__add = function ( lhs, rhs )
	local ret = {}
	ret.x = lhs.x + rhs.x
	ret.y = lhs.y + rhs.y

	return ret
end

setmetatable(v1, meta)
setmetatable(v2, meta)

local v3 = v1 + v2

print(v3.x, v3.y) -- 4, 6
模式描述
__add(a, b)a + b
__sub(a, b)a - b
__mul(a, b)a * b
__div(a, b)a / b
__mod(a, b)a % b
__pow(a, b)a ^ b
__unm(a)-a
__concat(a, b)a .. b
__eq(a, b)a == b
__lt(a, b)a < b
__le(a, b)a <= b

 

__call 元方法

把table当做函数调用


local meta = {}

meta.__call = function ( t1, t2 )
    local sum = 0
    
	for _, v in pairs(t1) do
		sum = sum + v
	end
    
    for _, v in pairs(t2) do
        sum = sum + v
    end

    return sum
end

local newTable = { 1, 2 }
setmetatable(newTable, meta)
-- 上面两行,可写成 local newTable = setmetatable({ 1, 2 }, meta)

print(newTable({3, 4, 5})) -- 15

 __tostring

 


local meta = {}

meta.__tostring = function ( t )
    local ret = ""
    
	for _, v in pairs(t) do
		ret = ret .. " " .. v
	end

    return "表元素: " .. ret
end

local newTable = setmetatable({1, 2, 3, 4}, meta)

print(newTable) -- 表元素:  1 2 3 4

用法实例:

local Stack = { data = {} }

function Stack:new()
	self.__index = self

	return setmetatable({ data = {} }, self)
end

function Stack:add(name, age)
	table.insert(self.data, {["name"] = name, ["age"] = age})
end

function Stack:get( name )
	for k, v in pairs(self.data) do
		if v.name == name then
			return v, k
		end
	end

	return nil, 0
end

function Stack:getByIdx( idx )
	return self.data[idx]
end

function Stack:size()
	return #self.data
end

local studentList = Stack:new()
studentList:add("小明", 10)
studentList:add("小红", 12)
studentList:add("小兰", 11)

local s1 = studentList:get("小兰")

print(s1.name .. "  " .. s1.age) -- 小兰  11
print("学生数量: " .. studentList:size()) -- 学生数量: 3

 

--默认值
function setDefault ( t , default )
	local mt = {}
	mt.__index = function ( )
		return default
	end

	setmetatable(t , mt)
end
 
local v = { x = 1 ,y = 2 }
print(v.x , v.y , v.z) -- 1 2 nil

-- 设置默认值
setDefault(v, 0)

print(v.x , v.y , v.z) -- 1 2 0
 
 
--只读属性
function setReadOnly ( t )
	local mt = {}
	mt.__index = t
	mt.__newindex = function (  )
		print("it's a readOnly table")
	end

	return setmetatable({} , mt) 
end

local data = setReadOnly({ 1, 2, 3, 4 })

print(1) -- 1
data[1] = 11 -- it's a readOnly table

 

### Lua元表的使用方法 在 Lua 编程语言中,元表metatable)是一种强大的特性,允许程序员自定义表格的行为。通过设置特定字段,可以改变或扩展表格的操作方式。 #### 创建并应用元表 要创建一个带有元表的对象,首先需要创建一个普通的 Lua 表格,之后再为此表格关联一个新的或已存在的元表: ```lua local myTable = {} -- 定义一个新表 setmetatable(myTable, {__index = function(t,k) return k.." not found." end}) print(myTable.anyKey) -- 输出 'anyKey not found.' ``` 上述代码展示了如何利用 `__index` 这一特殊的键来处理未找到索引的情况[^1]。 #### 使用内置事件触发器 除了 `__index` 外,还有其他多种可用于控制不同操作行为的方法,比如当尝试给不存在的成员赋值时会调用 `__newindex`; 当两个对象相加时则可能涉及到了 `__add` 方法等。下面的例子演示了怎样实现自定义加法运算逻辑: ```lua -- 自定义向量类及其算术运算符重载 Vector = {} function Vector.new(x,y) local v={x=x or 0, y=y or 0} setmetatable(v,{ __add=function(a,b)return Vector.new(a.x+b.x,a.y+b.y)end, __tostring=function(self)return "("..self.x..","..self.y..")"end }) return v end v1=Vector.new(1,2) v2=Vector.new(-3,-4) print((v1+v2)) --> (-2,-2) ``` 这段程序片段不仅实现了简单的二维矢量之间的加法计算,还提供了友好的字符串表示形式以便于调试输出。 #### 继承机制模拟 借助元表还可以轻松模仿面向对象编程中的继承概念。这里给出了一种简单的方式来进行基类与派生类之间属性共享的设计模式: ```lua BaseClass = { baseMethod = function() print("This is Base Class Method.") end; } DerivedClass = {} setmetatable(DerivedClass,{__index=BaseClass}) derivedInstance = DerivedClass() derivedInstance.baseMethod() -- 调用了来自父级的方法 ``` 此段脚本说明了子类可以从超类那里获取公共接口而无需重复声明相同的功能函数。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值