lua元表详解
元表的作用
元表是用来定义对table或userdata操作方式的表
举个例子
local t1 = {1}
local t2 = {2}
local t3 = t1 + t2
我们直接对两个table执行+运算,会报错
lua: /usercode/file.lua:3: attempt to perform arithmetic on local 't1' (a table value)
因为程序不知道如何对两个表执行+运行,这时候就需要通过元表来定义如何执行t1的+运算,有点类似于c语言中的运算符重载。
local mt = {}
--定义mt.__add元方法(其实就是元表中一个特殊的索引值)为将两个表的元素合并后返回一个新表
mt.__add = function(t1,t2)
local temp = {}
for _,v in pairs(t1) do
table.insert(temp,v)
end
for _,v in pairs(t2) do
table.insert(temp,v)
end
return temp
end
local t1 = {1,2,3}
local t2 = {2}
--设置t1的元表为mt
setmetatable(t1,mt)
local t3 = t1 + t2
--输出t3
local st = "{"
for _,v in pairs(t3) do
st = st..v..", "
end
st = st.."}"
print(st)
结果为:
{1, 2, 3, 2, }
因为程序在执行t1+t2的时候,会去调用t1的元表mt的__add元方法进行计算。
具体的过程是:
1.查看t1是否有元表,若有,则查看t1的元表是否有__add元方法,若有则调用。
2.查看t2是否有元表,若有,则查看t2的元表是否有__add元方法,若有则调用。
3.若都没有则会报错。
所以说,我们通过定义了t1元表的__add元方法,达到了让两个表通过+号来相加的效果
元表的元方法
| 函数 | 描述 |
|---|---|
| __add | 运算符 + |
| __sub | 运算符 - |
| __mul | 运算符 * |
| __ div | 运算符 / |
| __mod | 运算符 % |
| __unm | 运算符 -(取反) |
| __concat | 运算符 .. |
| __eq | 运算符 == |
| __lt | 运算符 < |
| __le | 运算符 <= |
| __call | 当函数调用 |
| __tostring | 转化为字符串 |
| __index | 调用一个索引 |
| __newindex | 给一个索引赋值 |
由于那几个运算符使用类似,所以就不单独说明了,接下来说 __call, __tostring, __index, __newindex四个元方法。
__call
__call可以让table当做一个函数来使用。
local mt = {}
--__call的第一参数是表自己
mt.__call = function(mytable,...)
--输出所有参数
for _,v in ipairs{...} do
print(v)
end
end
t = {}
setmetatable(t,mt)
--将t当作一个函数调用
t(1,2,3)
结果:
1
2
3
__tostring
__tostring可以修改table转化为字符串的行为
local mt = {}
--参数是表自己
mt.__tostring = function(t)
local s = "{"
for i,v in ipairs(t) do
if i > 1 then
s = s..", "
end
s = s..v
end
s = s .."}"
return s
end
t = {1,2,3}
--直接输出t
print(t)
--将t的元表设为mt
setmetatable(t,mt)
--输出t
print(t)
结果:
table: 0x14e2050
{1, 2, 3}
__index
调用table的一个不存在的索引时,会使用到元表的__index元方法,和前几个元方法不同,__index可以是一个函数也可是一个table。
作为函数:
将表和索引作为参数传入__index元方法,return一个返回值
local mt = {}
--第一个参数是表自己,第二个参数是调用的索引
mt.__index = function(t,key)
return "it is "..key
end
t = {1,2,3}
--输出未定义的key索引,输出为nil
print(t.key)
setmetatable(t,mt)
--设置元表后输出未定义的key索引,调用元表的__index函数,返回"it is key"输出
print(t.key)
结果:
nil
it is key
作为table:
查找__index元方法表,若有该索引,则返回该索引对应的值,否则返回nil
local mt = {}
mt.__index = {key = "it is key"}
t = {1,2,3}
--输出未定义的key索引,输出为nil
print(t.key)
setmetatable(t,mt)
--输出表中未定义,但元表的__index中定义的key索引时,输出__index中的key索引值"it is key"
print(t.key)
--输出表中未定义,但元表的__index中也未定义的值时,输出为nil
print(t.key2)
结果:
nil
it is key
nil
__newindex
当为table中一个不存在的索引赋值时,会去调用元表中的__newindex元方法
作为函数
__newindex是一个函数时会将赋值语句中的表、索引、赋的值当作参数去调用。不对表进行改变
local mt = {}
--第一个参数时表自己,第二个参数是索引,第三个参数是赋的值
mt.__newindex = function(t,index,value)
print("index is "..index)
print("value is "..value)
end
t = {key = "it is key"}
setmetatable(t,mt)
--输出表中已有索引key的值
print(t.key)
--为表中不存在的newKey索引赋值,调用了元表的__newIndex元方法,输出了参数信息
t.newKey = 10
--表中的newKey索引值还是空,上面看着是一个赋值操作,其实只是调用了__newIndex元方法,并没有对t中的元素进行改动
print(t.newKey)
结果:
it is key
index is newKey
value is 10
nil
作为table
__newindex是一个table时,为t中不存在的索引赋值会将该索引和值赋到__newindex所指向的表中,不对原来的表进行改变。
local mt = {}
--将__newindex元方法设置为一个空表newTable
local newTable = {}
mt.__newindex = newTable
t = {}
setmetatable(t,mt)
print(t.newKey,newTable.newKey)
--对t中不存在的索引进行负值时,由于t的元表中的__newindex元方法指向了一个表,所以并没有对t中的索引进行赋值操作将,而是将__newindex所指向的newTable的newKey索引赋值为了"it is newKey"
t.newKey = "it is newKey"
print(t.newKey,newTable.newKey)
结果:
nil nil
nil it is newKey
rawget 和 rawset
有时候我们希望直接改动或获取表中的值时,就需要rawget和rawset方法了。
rawget可以让你直接获取到表中索引的实际值,而不通过元表的__index元方法。
local mt = {}
mt.__index = {key = "it is key"}
t = {}
setmetatable(t,mt)
print(t.key)
--通过rawget直接获取t中的key索引
print(rawget(t,"key"))
结果:
it is key
nil
rawset可以让你直接为表中索引的赋值,而不通过元表的__newindex元方法。
local mt = {}
local newTable = {}
mt.__newindex = newTable
t = {}
setmetatable(t,mt)
print(t.newKey,newTable.newKey)
--通过rawset直接向t的newKey索引赋值
rawset(t,"newKey","it is newKey")
print(t.newKey,newTable.newKey)
结果:
nil nil
it is newKey nil
元表的使用场景
作为table的元表
通过为table设置元表可以在lua中实现面向对象编程。
作为userdata的元表
通过对userdata和元表可以实现在lua中对c中的结构进行面向对象式的访问。
lua元表详解的更多相关文章
- Lua Coroutine详解
协同程序与线程差不多,也就是一条执行序列,拥有自己独立的栈,局部变量和指令指针,同时又与其它协同程序共享全局变量和其它大部分东西.线程与协同程序的主要区别在于,一个具有多线程的程序可以同时运行几个线程 ...
- cocos2dx-3.x 导出自定义类到 lua 过程详解
转载请注明出处:http://www.cnblogs.com/Ray1024 一.简介 最近正在学习cocos2d中的lua游戏开发,因为lua开发的热更新特性,大家开发游戏好像都会优先选择lua作为 ...
- 游戏算法中lua脚本详解
此外,函数本身也是一个变量,比如: dp@dp:~ % cat test.lua local mylen={} mylen.len3=function (x,y,z) return math.sqrt ...
- 【精选】Nginx模块Lua-Nginx-Module学习笔记(二)Lua指令详解(Directives)
源码地址:https://github.com/Tinywan/Lua-Nginx-Redis Nginx与Lua编写脚本的基本构建块是指令. 指令用于指定何时运行用户Lua代码以及如何使用结果. 下 ...
- Nginx模块Lua-Nginx-Module学习笔记(二)Lua指令详解(Directives)
源码地址:https://github.com/Tinywan/Lua-Nginx-Redis Nginx与Lua编写脚本的基本构建块是指令. 指令用于指定何时运行用户Lua代码以及如何使用结果. 下 ...
- Lua的协程和协程库详解
我们首先介绍一下什么是协程.然后详细介绍一下coroutine库,然后介绍一下协程的简单用法,最后介绍一下协程的复杂用法. 一.协程是什么? (1)线程 首先复习一下多线程.我们都知道线程——Thre ...
- 详解LUA开发工具及其环境配置
LUA开发工具及其环境配置是本文要介绍的内容,主要是来了解并学习lua开发工具的使用和环境的配置,第一次接触LUA的话,就跟本人一起学习吧.看我能不能忽悠到你. LUA是语言,那么一定有编写的工具.第 ...
- Lua包管理工具Luarocks详解 - 15134559390的个人空间 - 开源中国社区
Lua包管理工具Luarocks详解 - 15134559390的个人空间 - 开源中国社区 Lua包管理工具Luarocks详解
- Cocos 2d-X Lua 游戏添加苹果内购(二) OC和Lua交互代码详解
这是第二篇 Cocos 2d-X Lua 游戏添加苹果内购(一) 图文详解准备流程 这是前面的第一篇,详细的说明了怎样添加内购项目以及填写银行信息提交以及沙盒测试员的添加使用以及需要我们注意的东西,结 ...
随机推荐
- 警告: [SetPropertiesRule]{Server/Service/Engine/Host/Context}Setting property 'source' to 'org.eclipse
当你用Eclipse运行web项目的时候,你就会看到控制台出现:WARNING: [SetPropertiesRule]{Server/Service/Engine/Host/Context} Set ...
- Spring学习(十九)----- Spring与WEB容器整合
首先可以肯定的是,加载顺序与它们在 web.xml 文件中的先后顺序无关.即不会因为 filter 写在 listener 的前面而会先加载 filter.最终得出的结论是:listener -> ...
- Js_闭包跟作用域
作用域的嵌套将形成作用域链,函数的嵌套将形成闭包.闭包与作用域链是 JavaScript 区别于其它语言的重要特性之一. 作用域 JavaScript 中有两种作用域:函数作用域和全局作用域. 在一个 ...
- LevelDB原理解析
LevelDb有如下一些特点: 首先,LevelDb是一个持久化存储的KV系统,和Redis这种内存型的KV系统不同,LevelDb不会像Redis一样狂吃内存,而是将大部分数据存储到磁盘上. 其次, ...
- 2-Thirteenth Scrum Meeting-10151213
任务安排 成员 今日完成 明日任务 闫昊 获取视频播放进度 用本地数据库记录课程结构和学习进度 唐彬 阅读IOS代码+阅读上届网络核心代码 请假(编译……) 史烨轩 下载service开发 ...
- 2-Twelfth Scrum Meeting20151212
任务安排 成员 今日完成 明日任务 闫昊 获取视频播放的进度 获取视频播放进度 唐彬 解决handler可能引起的内存泄露问题 阅读IOS代码+阅读上届网络核心代码 史烨轩 下载service开发 ...
- 20135234mqy-——信息安全系统设计基础第十二周学习总结
process environ.c environvar.c consumer.c 管道写端 producer.c 管道读端 testmf.c listargs.c pipedemo.c 管道 pip ...
- 【菜鸟】RESTful 架构详解
RESTful 架构详解 分类 编程技术 1. 什么是REST REST全称是Representational State Transfer,中文意思是表述(编者注:通常译为表征)性状态转移. 它首次 ...
- layout图形化界面看不到内容 Failed to find the style corresponding to the id
1.问题 在创建新的工程的时候,选择目标SDK为api21,编译SDK为api23.创建出来的layout文件图形化界面中看不到,并且报错: Failed to find the style corr ...
- KM算法 PK 最小费用最大流
用到了KM算法 ,发现自己没有这个模板,搜索学习一下上海大学final大神,http://www.cnblogs.com/kuangbin/p/3228861.html #include <st ...