[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使得你可以像调用函数一样调用tablet = 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/
相关文章推荐
- [LeetCode]Evaluate Reverse Polish Notation
- vs插件 BabelLua的使用
- Lua for学习
- lua 首次编译
- Lua查找表元素过程(元表、__index方法是如何工作的)
- lua动态链接库(luaopen_*函数的使用)
- [Lua]Mac系统上安装Lua环境
- lua-md5 for lua5.3
- Lua 运行
- 浅析Lua中table的遍历和删除
- Lua5.2.3源码阅读(2)-Table
- Lua5.2.3源码阅读(3)-Table(ipairs,pairs)
- Lua基础和Lua版飞机大战
- c++获取lua嵌套table某属性的值
- Lua5.2.3源码阅读(2)-Table
- [leetcode] 150.Evaluate Reverse Polish Notation
- Lua5.1.4代码分析(二十三)-如何实现Lua代码的热更新
- lua 说明self,点号或冒号的关系
- Lua5.2.3源码阅读(1)-TValue,TString
- Lua(基础)