lua的元表
来源:互联网 发布:淘宝商城男装秋装 编辑:程序博客网 时间:2024/04/30 01:16
lua的元表
- metatable
- 入门
- lua
metatable是Lua中的重要概念,每一个table都可以加上metatable,以改变相应的table的行为。让我们看一个例子:
t = {} -- 普通的tablemt = {} -- metatablesetmetatable(t, mt) -- 设定mt为t的metatablegetmetatable(t) -- 返回mt
使用getmetatable
和setmetatable
来查看和设定metatable。当然,上面的代码也可以压缩成一行:
t = setmetatable({}, {})
这是因为setmetatable
会返回它的第一个参数。
metatable可以包括任何东西,metatable特有的键一般以__
开头,例如__index
和__newindex
,它们的值一般是函数或其他table。
t = setmetatable({}, { __index = function(t, key) if key == "foo" then return 0 else return table[key] end end})
__index
这是metatable最常用的键了。
当你通过键来访问table的时候,如果这个键没有值,那么Lua就会寻找该table的metatable(假定有metatable)中的__index
键。如果__index
包含一个表格,Lua会在表格中查找相应的键。
other = { foo = 3 }t = setmetatable({}, { __index = other })t.foo -- 3t.bar -- nil
如果__index
包含一个函数的话,Lua就会调用那个函数,table和键会作为参数传递给函数。
__newindex
类似__index
,__newindex
的值为函数或table,用于按键赋值的情况。
other = {}t = setmetatable({}, { __newindex = other })t.foo = 3other.foo -- 3t.foo -- nilt = setmetatable({}, { __newindex = function(t, key, value) if type(value) == "number" then rawset(t, key, value * value) else rawset(t, key, value) end end})t.foo = "foo"t.bar = 4t.la = 10t.foo -- "foo"t.bar -- 16t.la -- 100
上面的代码中使用了rawget
和rawset
以避免死循环。使用这两个函数,可以避免Lua使用__index
和__newindex
。
运算符
利用metatable可以定义运算符,例如*
:
t = setmetatable({ 1, 2, 3 }, { __mul = function(t, other) new = {} for i = 1, other do for _, v in ipairs(t) do table.insert(new, v) end end return new end})t = t * 2 -- { 1, 2, 3, 1, 2, 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})t(1, 2, 3, 4) -- 24
这是很有用的特性。需要以直接调用table的形式调用table中的某个(默认)函数的时候,使用__call
设定很方便。例如,kikito的tween.lua,就用了这个技巧,这样直接调用tween
就可以调用tween.start
。再如MiddleClass中,类的new
方法可以通过直接调用类的方式调用。
__tostring
最后讲下__tostring
,它可以定义如何将一个table转换成字符串,经常和print
配合使用,因为默认情况下,你打印table的时候会显示table: 0x<16进制数字>
:
t = setmetatable({ 1, 2, 3 }, { __tostring = function(t) sum = 0 for _, v in pairs(t) do sum = sum + v end return "Sum: " .. sum end})print(t) -- prints out "Sum: 6"
例子
综合运用以上知识,我们编写一个2D矢量类:
Vector = {}Vector.__index = Vectorfunction Vector.__add(a, b) if type(a) == "number" then return Vector.new(b.x + a, b.y + a) elseif type(b) == "number" then return Vector.new(a.x + b, a.y + b) else return Vector.new(a.x + b.x, a.y + b.y) endendfunction Vector.__sub(a, b) if type(a) == "number" then return Vector.new(b.x - a, b.y - a) elseif type(b) == "number" then return Vector.new(a.x - b, a.y - b) else return Vector.new(a.x - b.x, a.y - b.y) endendfunction Vector.__mul(a, b) if type(a) == "number" then return Vector.new(b.x * a, b.y * a) elseif type(b) == "number" then return Vector.new(a.x * b, a.y * b) else return Vector.new(a.x * b.x, a.y * b.y) endendfunction Vector.__div(a, b) if type(a) == "number" then return Vector.new(b.x / a, b.y / a) elseif type(b) == "number" then return Vector.new(a.x / b, a.y / b) else return Vector.new(a.x / b.x, a.y / b.y) endendfunction Vector.__eq(a, b) return a.x == b.x and a.y == b.yendfunction Vector.__lt(a, b) return a.x < b.x or (a.x == b.x and a.y < b.y)endfunction Vector.__le(a, b) return a.x <= b.x and a.y <= b.yendfunction Vector.__tostring(a) return "(" .. a.x .. ", " .. a.y .. ")"endfunction Vector.new(x, y) return setmetatable({ x = x or 0, y = y or 0 }, Vector)endfunction Vector.distance(a, b) return (b - a):len()endfunction Vector:clone() return Vector.new(self.x, self.y)endfunction Vector:unpack() return self.x, self.yendfunction Vector:len() return math.sqrt(self.x * self.x + self.y * self.y)endfunction Vector:lenSq() return self.x * self.x + self.y * self.yendfunction Vector:normalize() local len = self:len() self.x = self.x / len self.y = self.y / len return selfendfunction Vector:normalized() return self / self:len()endfunction Vector:rotate(phi) local c = math.cos(phi) local s = math.sin(phi) self.x = c * self.x - s * self.y self.y = s * self.x + c * self.y return selfendfunction Vector:rotated(phi) return self:clone():rotate(phi)endfunction Vector:perpendicular() return Vector.new(-self.y, self.x)endfunction Vector:projectOn(other) return (self * other) * other / other:lenSq()endfunction Vector:cross(other) return self.x * other.y - self.y * other.xendsetmetatable(Vector, { __call = function(_, ...) return Vector.new(...) end })
原文 Lua Metatables Tutorial
翻译 SegmentFault
- lua的元表
- lua的元表
- lua的元表
- lua元表的理解
- Lua元表的使用
- LUA元表的正确理解
- lua 的元表和元表的__index字段
- LUA元表、元操作
- Lua 元表 元方法
- lua 元表 __index 继承的实现
- Lua 的元表怎么理解
- Lua元表的基础示例。
- Lua元表的定义和使用
- lua 元表
- lua元表学习
- lua元表
- lua元表
- lua元表
- Fixed: The Windows Process Activation Service service terminated with the following error: The system cannot find the file speci
- android预编译apk的深入思考
- 错位展示top按钮组
- process monitor教程汇总
- Java中设置classpath、path、JAVA_HOME的作用
- lua的元表
- 声明式事务
- Java中JAVA_HOME与CLASSPATH的解析(转)
- 正则表达式通配符及vim
- cin.get()、流和缓冲区
- python opencv cv2 基础操作3 CascadeClassifier
- [基础] 子查询的用法
- C++指针与数组
- freeRTOS xTaskCreate使用示例