Lua中的元表和元方法
来源:互联网 发布:人工智能安防公司 编辑:程序博客网 时间:2024/04/27 23:02
元方法会检测一个操作中的值是否有元表,以及元表是否定义了操作的元方法。如两个table相加,先检查两者之一是否有元表,之后检查是否有一个叫“__add”的字段,若找到,则调用对应的值。“__add”等字段,其对应的值(一般是一个函数或是table)就是“元方法”。
1、元表定义
元表是普通的Lua表。元表中的键为事件(event),称值为元方法(metamethod),通过设置特定的字段来改变作用于该值的操作的某些行为特征。
例如,当数字值作为加法的操作数时,Lua检查其元表中的"__add"字段是否有个函数。如果有,Lua调用它执行加法,其事件是"add",元方法是执行加法的函数。
2、元表的设置和获取
可通过函数getmetatable查询任何值的元表。
可通过函数setmetatable替换表的元表。
1)元表设置元方法
例子1:
表加法的元方法的代码例子如下:
function add(t1,t2)--"#"运算符取表长度assert(#t1 == #t2)local length = #t1for i = 1,length dot1[i] = t1[i] + t2[i]endreturn t1end--setmetatable 设置表的元方法__add,支持表之间的加法,返回被设置的表t1 = setmetatable({1,2,3},{__add = add})t2 = setmetatable({10,20,30},{__add = add})t1 = t1 + t2 -- 表之间相加,返回相加后的表for i = 1 ,#t1 doprint(t1[i])end
输出结果:
11
22
33
例子2:
t = {}print(getmetatable(t)) --显示过元表 此时是nil--可以用setmetatable来设置或修改任何table的元表t1 = {}setmetatable(t,t1)assert(getmetatable(t) == t1)
2)有元表的类型
任何table可以作为任何值的元表,而一组相关的table可以共享一个通用的元表,此元表描述了一个共同的行为。一个tabel甚至可以作为它自己的元表,用于描述其特有行为。在lua中,只能设置table的元表。要设置其它类型的元表,必须通过C代码来完成.
print(getmetatable("hi")) --005DECD8 说明字符串有元表print(getmetatable(10)) --nil number没有元表
3)元表的索引表
__index表是作为提供查找方式的成员。
lua表的成员查找如下:
1.在表中查找,如果找到,返回该元素,找不到则继续
2.判断该表是否有元表,如果没有元表,返回nil,有元表则继续
3.判断元表有没有__index方法,如果__index方法为nil,则返回nil;
如果__index方法是一个表,则重复1、2、3;如果__index方法是一个函数,则返回该函数的返回值
方式1:
代码例子如下:
t = {}m = {a = "and",b = "lilei", c= "han meiemei"}setmetatable(t,{__index = m})--设置表的索引表for k,v in pairs(t) doprint(k,v)endprint ("---------")print (t.b,t.a,t.c)输出结果:
---------
lilei and han meiemei
方式2:
father = { house=1 } father.__index = father -- 把father的__index方法指向自己 son = { car=1 } setmetatable(son, father) print(son.house)
输出的结果为1
如果father.__index 是空的,则找不到对应的元素father = { house=1 } son = { car=1 } setmetatable(son, father) --把son的metatable设置为father print(son.house)
输出的结果是nil
3、元表的元方法
元表可以控制对象的数学运算、顺序比较、连接、取长、和索引操作的行为。元表也能定义用户数据被垃圾收集时调用的函数。
Lua给这些操作的每一个都关联了事件的特定键。当Lua对某值执行其中一个操作时,检查该值是否含有元表以及相应的键(和对应的事件)。若有,则根据与该键关联的值(元方法)来完成操作。
每个操作由相应的名字标识。每个操作的键是由其名字前缀两个下划线“__”的字符串;例如,操作“加(add)”的键是字符串"__add"。
(1)获取给定对象的元方法
方式如下。下面显示的Lua代码只是说明性的;真实的行为被硬编码到解释器中,并且比这里的模拟更加高效。
metatable(obj)[event]
它应被解读为
rawget(getmetatable(obj) or {}, event)
访问没有元表的对象或者该对象的元表没有该元方法,结果为nil。
(2)元方法的应用
1)并集和交集的元方法
Set = {} --集合local mt = {} --集合元表--根据参数列表中的值创建一个新的集合function Set.new(l) local set = {} setmetatable(set,mt) --指定 table set的元表为mt for k,v in ipairs(l) do set[v] = true --注意,是拿索来当数据用的 end return setendfunction Set.union(a,b) local res = Set.new{} for k,v in pairs(a) do res[k] = true end for k,v in pairs(b) do res[k] = true end return resendfunction Set.intersection(a,b) local res = Set.new{} for k,v in pairs(a) do if b[k] then res[k] = true--使用的是表res的键 end end return resendfunction Set.tostring(set) local l = {} for k,v in pairs(set) do--把键依次添加到表中 l[#l + 1] = k end return "{" .. table.concat(l,", ") .. "}"endfunction Set.print(s) print(Set.tostring(s))end--将元方法加入元表mt.__add = Set.union --指定加号为求并集的方法mt.__mul = Set.intersection --指定乘号为交集的方法s1 = Set.new({11,22,31,44,56})s2 = Set.new({66,33,22,31})s3 = s1 + s2 --求并集 Set.print(s3) --输出 {11, 31, 66, 22, 33, 56, 44}s4 = s1 * s2 --求交集Set.print(s4) --输出 {31, 22}
2)关系等元方法
关系是指 __eq(等于)、__lt(小于)等
mt.__le = function(a,b)--小于等于 for k in pairs(a) do--a元素都在b中则为true,否则为false if not b[k] then return false end end return trueendmt.__lt = function(a,b)--小于 return a<=b and not (b<=a)endmt.__eq = function(a,b) return a<=b and b<=aendss1 = Set.new{2,4}ss2 = Set.new{4,10,2}print(ss1<=ss2) --trueprint(ss1<ss2) --trueprint(ss1>=ss1) --trueprint(ss1>ss1) --falseprint(ss1 == ss2*ss1) --true
3)输出元方法
设置元表的__tostring字段
mt.__tostring = Set.tostring打印集合
sstext = Set.new{33,55,6666}print(sstext) --{55, 33, 6666}
4)元表保护
假设想要保护的元表,使用户即不能看也不能修改的元表。那么就需要用到__metatable。当设置了该字段时,getmetatable就会返回这个字段的值,而setmetatable会引发一个错误
设置元表代码:
mt.__metatable = "not your business"sstext1 = Set.new{} print(getmetatable(sstext1)) --not your businesssetmetatable(s1,{})
5)元表__index的函数访问方式
通过元表的__index元方法触发函数,访问对象的成员
Window = {}Window.prototype = {x=0,y=0,width = 100,height = 100}Window.mt = {}function Window.new(o) setmetatable(o,Window.mt) return oend--现在定义一个元方法Window.mt.__index = function(table,key)--table 类似于隐藏参数this return Window.prototype[key]endw = Window.new({x=10,y=20})print(w.width) -- 100 实际上访问的是prototype的width字段,通过元表的__index元方法触发
6)元表的__newindex元方法
与__index不同的是__index是在查询的时候用的,而_newindex是在更新的时候用的
7)设置表默认值
通过元表设置表的默认值
function setDefault(t,d) local mt = {__index = function() return d end} setmetatable(t,mt)end
8)通过元表设置表的代理
local _t = {} --_t表是实际存储结构t = {} --t表是访问代理--元表mt是t表的元表(提供访问接口)local mt = { __index = function(t,k) print("access to element " .. tostring(k)) return _t[k] end, __newindex = function(t,k,v) print("update of element " .. tostring(k) .. " to " .. tostring(v)) _t[k] = v end}setmetatable(t,mt)t[2] = "hello" --输出: update of element 2 to helloprint(t[2]) --输出: access to element 2
9)元表设置表的读权限
通过__newindex来限制表的修改权限,将8)中的代码__newindex元方法修改为:
__newindex = function(t,k,v) assert(0)--实际上没干事情end
lua的参考手册:http://www.codingnow.com/2000/download/lua_manual.html
- Lua 中的元表和元方法
- Lua中的元表和元方法
- Lua中的元表和元方法
- Lua中的元表和元方法
- Lua中的元表和元方法
- Lua中的元表和元方法
- Lua中的元表和元方法
- Lua中的元表和元方法
- Lua中的元表和元方法
- lua中的元表和元方法
- lua中的元表和元方法解析
- Lua中的元表与元方法
- Lua中的元表与元方法
- Lua中的元表与元方法
- Lua中的元表与元方法
- Lua中的元表与元方法
- Lua元表和元方法
- Lua 元表和元方法
- 《算法导论》学习笔记 第一章&&第二章&&第三章
- 对HashMap值进行排序java代码
- Shell脚本学习(一):shell变量和一些常用命令
- 计算斐波那契数列,两种方法,打开注释掉的语句你会感受到算法的力量
- Android 数据库存取图片
- Lua中的元表和元方法
- 数据结构学习笔记--(2)数组
- Nine Interlinks
- 黑马程序员-(2)Java语法基础知识框架
- 最简单的左右滑动翻页案例
- 黑马程序员-(3)Java语法经典列子
- 堆排序 C++
- SetWindowPos cannot overload 7个参数? (SDK API 与 MFC API的区别)
- 黑马程序员-(4)Java基础语法之函数