您的位置:首页 > 编程语言 > Lua

[Lua]Lua高级教程Metatables

2015-07-16 16:47 417 查看

什么是Metatable

metatable是Lua中的重要概念,每一个table都可以加上metatable,以改变相应的table的行为。

Metatables举例

-- 声明一个正常的关系变量
lo_table = {}

-- 声明空元表变量
lo_meta_table = {}

-- 为关系变量t设置元表变量
setmetatable(lo_table, lo_meta_table)

-- 获取一个关系变量的元表变量
getmetatable(lo_table)


上边的代码也可以写成一行,如下所示

-- setmetatable函数的返回值,就是该函数的第一个参数
lo_table = setmetatable({}, {})


创建复杂的元表变量

metatable可以包括任何东西,metatable特有的键一般以
__
开头,例如
__index
__newindex
,它们的值一般是函数或其他table。

lo_table = setmetatable({}, {
__index = function(lo_table, key)
if key == "foo" then
return 0
else
return table[key]
end
end
})


__index

  这是metatable最常用的键了。

  当你通过键来访问table的时候,如果这个键没有值,那么Lua就会寻找该table的metatable(假定有metatable)中的
__index
键。如果
__index
包含一个表格,Lua会在表格中查找相应的键。

-- 创建元表变量
lo_meta_table = { name = "蓝鸥" }

-- 设置该元表变量作为关系变量的
lo_table = setmetatable({}, { __index = lo_meta_table })

-- 打印lo_table变量的姓名 蓝鸥
print(lo_table.name)

-- 打印lo_table变量年龄 nil
print(lo_table.age)


  如果
__index
包含一个函数的话,Lua就会调用那个函数,table和键会作为参数传递给函数。

-- 创建元表变量
lo_meta_table = {
name = "蓝鸥" ,
action = function ( param )
-- body
if(param == "学生") then
print("让教育回归本质")
else
print("让蓝鸥维护教育")
end
end
}

-- 设置该元表变量作为关系变量的
lo_table = setmetatable({}, { __index = lo_meta_table })

-- 打印lo_table变量的动作 让教育回归本质
print(lo_table.action("学生"))

-- 打印lo_table变量的动作 让蓝鸥维护教育
print(lo_table.action("肖浩"))

-- 打印lo_table变量年龄 nil
print(lo_table.age)


__newindex

类似
__index
__newindex
的值为函数或table,用于按键赋值的情况。

-- 创建元表变量
lo_meta_table = {}

-- 设置该元表变量作为关系变量的
lo_table = setmetatable({}, { __newindex = lo_meta_table })

-- 设置lo_table变量的name关键字的值
lo_table.name = "蓝鸥"

-- 打印lo_meta_table元表变量name关键字的值值
print(lo_meta_table.name)

-- 打印lo_table变量name关键字的值
print(lo_table.name)


-- 创建元表变量
lo_meta_table = {}

-- 设置该元表变量作为关系变量的
lo_table = setmetatable({}, { __newindex = function(t, key, value)
if type(value) == "number" then
rawset(t, key, value * value)
else
rawset(t, key, value)
end
end
})

-- 设置lo_table变量的name关键字的值
lo_table.name = "蓝鸥"

-- 设置lo_table变量的age关键字的值
lo_table.age = 3

-- 打印lo_meta_table元表变量name关键字的值值
print(lo_meta_table.name)

-- 打印lo_table变量name关键字的值
print(lo_table.name)

-- 打印lo_meta_table元表变量age关键字的值值
print(lo_meta_table.age)

-- 打印lo_table变量age关键字的值
print(lo_table.age)


上面的代码中使用了
rawget
rawset
以避免死循环。使用这两个函数,可以避免Lua使用
__index
__newindex


运算符

利用metatable可以定义运算符,例如
+


-- 创建重载+号行为的表变量
lo_table = setmetatable({ 1, 2, 3 }, {
__add = function(lo_table, other)
new = {}

-- 遍历元素加other
for _, v in ipairs(lo_table)
do table.insert(new, v + other)
end

return new
end
})

-- 进行计算+
lo_table = lo_table + 2

-- 打印得到的结果
print(lo_table[1])
print(lo_table[2])
print(lo_table[3])


__index
__newindex
不同,
__mul
的值只能是函数。与
__mul
类似的键有:

__add
(+)

__sub
(-)

__div
(/)

__mod
(%)

__unm
取负

__concat
(..)

__eq
(==)

__lt
(
<
)

__le
(
<=
)

__call

__call使得你可以像调用函数一样调用table

t = setmetatable({}, {
__call = function(t, a, b, c, whatever)
return (a + b + c) * whatever
end
})

local result = t(1, 2, 3, 4)
print(result)


__tostring

最后讲下__tostring,它可以定义如何将一个table转换成字符串,经常和 print 配合使用,因为默认情况下,你打印table的时候会显示 table: 0x7f86f3d04d80 这样的代码

lo_table = setmetatable({ 1, 2, 3 }, {
__tostring = function(lo_table)
sum = 0
for _, v in pairs(lo_table)
do
sum = sum + v
end

return "计算的结果是: " .. sum
end
})

-- prints out "计算的结果是: 6"
print(lo_table)


创建一个简单的向量Vector类

Vector = {}
Vector.__index = Vector

function Vector.new(x, y)
return setmetatable({ x = x or 0, y = y or 0 }, Vector)
end

-- __call关键字
setmetatable(Vector, { __call = function(_, ...) return Vector.new(...) end })

-- + 运算符
function Vector:__add(other)
-- ...
local result = Vector(self.x + other.x,self.y + other.y)

return result
end

-- __tostring关键字
function Vector:__tostring()
-- body

return "x: " .. self.x .. " y: " .. self.y

end

a = Vector.new(12, 10)
b = Vector(20, 11)
c = a + b

print(a)
print(c)


原文链接:http://nova-fusion.com/2011/06/30/lua-metatables-tutorial/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: