Lua 元表及常见元方法
一、什么是元表
Lua 中的 table 使用起来有点像c++中的 map 或者 unordered_map ,都是通过对应的key 获取对应的value。如果访问了表中不存在的key时,就会触发Lua的一种机制,Lua也正是凭借这个机制可以用来模拟类似“继承”的行为,具体可以参考上一篇文章Lua中self 、自索引及其面向对象应用代码示例。
元表用来定义一个table在面对未知操作时候的行为,比如,对于a b 两个table,是无法进行相加操作 即:a+b 会报错。
比如:
a, b = {1, 2, 3}, {10, 20}c = a + b
print(c) -- 输出的是a的地址
定义了两张表 a 和 b,当Lua执行到 a + b 时就会报错,因为Lua不知道如何将两个table相加。
元表两个重要的方法
setmetatable(tab, meta_tab) --设置tab的元表为meta_tabgetmetatable(tab) -- 获取tab的元表
后续的例子中,会再详细讲解两个方法的用法。
二、元方法
2.1 通过元表实现两个table的相加
定义一个元表meta_ta, 并且实现 __add 方法,然后通过 setmetatable(a, meta_ta) 将meta_ta设置为a的元表 。此时,当Lua 执行到 a+b ,会先检查a 或 b 有没有元表,如果有元表且元表中实现了 __add ,就调用该key对应的值,__add对应的值(函数或者table)就是“元方法”。如果 a 和 b 都有元表会执行a的元表。
a, b = {1, 2, 3}, {10, 20}-- print(a + b) meta_ta = {__add = function(t1, t2)for k, v in pairs(t2) do-- 将表t2中的元素追加到t1中table.insert(t1, v)endreturn t1end
}setmetatable(a, meta_ta)c = a + b
print(c) -- 输出的是a的地址for k, v in pairs(c) doprint(k, v)
end
运行结果:
运算符相关的元方法除了 __add 还有 减法 乘法 除法 取模 大于 小于 等等
2.2 Table常用的元方法
__index 元方法
当我们访问表中一个不存在的字段时,得到的结果会是nil。但时,如果为该表设置了元表,访问的时候解释器就会去元表查找一个名为 __index 的元方法,如果没有这个元方法,返回nil,否则,由这个元方法来提供最终结果。
-- 定义表t2
t2 = {id = 1, name = "panda", age = 25}-- 1. 显式指定meta_t2 为 t2 的元表
-- meta_t2 = {}
-- setmetatable(t2, meta_t2)
-- meta_t2.__index = { addr = "beijing"}-- 2. 隐式指定元表(匿名元表)
setmetatable(t2, {-- __index 是个表-- __index = { addr = "beijing"}-- __index 是function__index = function(t, k)print(t, k) -- 输出 表t的地址 和 keyt[k] = "深圳" -- 为 表t 添加kvreturn "北京"end,})print(t2.name) -- 输出 pandaprint(t2.addr) -- 输出biao t2 的地址 和 key: addr 及返回值 北京print(t2.addr) -- 因为已经成功添加kv 直接输出
运行结果:
分析:
- 表 t2 中有name字段,直接返回
- 表 t2 中没有 addr 字段,就会找 t2 的元表,看元表中有没有__index 字段,找到后调用对应的值。
Lua 读取表中元素的规则如下:
- 在表中查找,如果找到,返回该元素,找不到则继续
- 判断该表是否有元表,如果没有元表,返回 nil,有元表则继续
- 判断元表有没有 __index 方法,如果 __index 方法为 nil,则返回 nil;如果 index 方法是一个表,则重复 1、2、3;如果 __index 方法是一个函数,Lua会以表和键为参数调用该函数,并返回该函数的返回值
如果我们希望在访问一个表时不调用 __index 元方法,可以使用原生函数 rawget:
rawget(t2, addr) -- 输出 nil
__newindex 元方法
当查询表中一个不存在的字段时,Lua会从该表的元表中的 __index 继续寻找;当对表中一个不存在的字段进行赋值时,就会触发 __newindex 元方法,此时__newindex 的值需要分为两种情况:
(1)__newindex 指向的是一个表:
t3 = {id = 3, name = "lwang", age = 28}meta_t3 = {addr = "beijing"
}
meta_t3.__newindex = meta_t3 setmetatable(t3, meta_t3)print(t3.addr) -- nilprint(meta_t3.addr) -- beijing
t3.addr = "shenzhen"
print(t3.addr) -- nil t3 不存在addr字段,找元表meta_t3的__newindex 指向meta_t3表 会为meta_t3的addr赋值,而不进行自身赋值print(meta_t3.addr) -- shenzhen, 值被t3修改
运行结果:
(2)__newindex 指向的是函数:
t3 = {id = 3, name = "lwang", age = 28}meta_t3 = {addr = "beijing"
}
meta_t3.__newindex = function()print("这里是meta_t3 __newindex 元方法调用")
endsetmetatable(t3, meta_t3)t3.addr = "shenzhen" -- 输出:这里是meta_t3 __newindex 元方法调用
print(t3.addr) -- nil
运行结果:
__tostring 元方法
用来接管表的返回值,按照我们预定的格式输出,还是以两个表相加为例:
a, b = {1, 2, 3}, {10, 20}meta_ta = {__add = function(t1, t2)for k, v in pairs(t2) dotable.insert(t1, v)endreturn t1end,-- __tostring 接管本表的返回值,其中 .. 相当于c++中字符串拼接__tostring = function(t)s = ""for k, v in pairs(t) dos = s..v.." "endreturn send
}setmetatable(a, meta_ta)-- 如果不实现 __tostring 方法,直接 print(table) 打印出来是table的地址
print(a) -- 1 2 3c = a + b
print(c) -- 1 2 3 10 20
运行结果
__call 和 __gc 元方法
__call 可以让表以类似函数的方式那样调用,比如:tab(arg1, arg2 …)
__gc 有点像c++中析构函数,释放资源
t1 = {10, 20, 30}meta_t1 = {__call = function(t, ...)print(t, ...)end,--元表中用一个以字符串 " __gc " 为索引的域,那么就标记了这个对象需要触发终结器__gc = function()print("call gc func")end
}setmetatable(t1, meta_t1)t1("panda", 10, true) -- table: 0xafc780 panda 10 trueprint("app close..")
其中,__call 方法的第一个参数为表地址,剩余参数用…表示。
推荐一个零声学院免费教程,个人觉得老师讲得不错,
分享给大家:[Linux,Nginx,ZeroMQ,MySQL,Redis,
fastdfs,MongoDB,ZK,流媒体,CDN,P2P,K8S,Docker,
TCP/IP,协程,DPDK等技术内容,点击立即学习:
Lua 元表及常见元方法相关推荐
- Lua中强大的元方法__index详解
今天要来介绍比较好玩的内容--__index元方法 1.我是备胎,记得回头看看 咳咳,相信每一位女生都拥有或者不知不觉中拥有了一些备胎,啊,当然,又或许是成为过别人的备胎. 没有备胎的人,就不是完整的 ...
- lua的元表metatable及元方法
前言 元表对应的英文是metatable,元方法是metamethod.我们都知道,在C++中,两个类是无法直接相加的,但是,如果你重载了"+"符号,就可以进行类的加法运算.在Lu ...
- Lua程序设计 | 模块和包、泛型迭代器和for、元表和元方法
From<Programming in Lua> by Roberto Ierusalimschy 文章目录 模块和包 函数 require 模块重命名 搜索路径 搜索器 Lua语言中编写 ...
- Lua 学习元表,元方法
前言 Lua本身没有面向对象的思想,但是可以根据表.元表.元方法来靠近它 一.元表与元方法的概念 Lua中每个值都可具有元表.元表是普通的Lua表,定义了原始值在某些特定操作下 的行为.例如,当tab ...
- lua学习笔记之元表和元方法
元表允许当遇到未知操作时,改变值的行为.例如,使用元表,可以定义表a与表b的关系运算a+b.当lua尝试两个表相加时,会检查是否其中一个有元表并且元表是否有__add字段. 元表在面向对象的术语中是一 ...
- lua元表和元方法 《lua程序设计》 13章 读书笔记
lua中每个值都有一个元表,talble和userdata可以有各自独立的元表,而其它类型的值则共享其类型所属的单一元表.lua在创建table时不会创建元表. t = {} print(getmet ...
- lua 元表/元方法
在lua中,每个值都有其对应的操作,比如数值型有加减乘除等操作,字符串型有连接截取等操作,那么这些操作(加减乘除,连接截取等)定义在什么地方呢?定义在这些值默认的元表中,如果想修改这些操作(比如加法) ...
- Lua语言编程学习之路02----第13章 元表与元方法
前言 在Lua中我们无法直接对两个table进行相加,无法对函数进行比较,也无法调用一个函数. 于是Lua可以通过修改一个值的行为,使其在面对一个非预定义的操作时执行一个自己实现的操作.比如两个t ...
- 【Lua进阶系列】lua元方法
[Lua进阶系列]之Lua元方法案例+字段 大家好,我是Lampard~~ 欢迎来到Lua进阶系列的博客 前文再续,书接上一回.今天和大家讲解一 ...
最新文章
- java arraylist优点_Java中各种集合的特点总结
- 社交网络图挖掘5--图的邻居性质
- springmvc静态资源拦截与访问
- java去除不为null,java – 选择特定字段不为NULL的所有记录
- Google、MS和BAT教给我的面试真谛
- Qt之QtCreator Qt5示例丢失解决方案
- java实现Beta函数
- Linux操作系统的VI命令
- how to set up github blog
- java名字自动生成_Java名字生成器
- repast HPC初探(运行其自带例子过程中出现的问题)
- bochs上网镜像怎么上网_【bochs win10镜像可上网版】bochs win10镜像img下载 完整版-趣致软件园...
- Northwind数据库练习及参考答案
- 网络分析仪测试线损_网络分析仪测试天线隔离度
- ASO关键词排名的三种优化方式,aso关键词排名优化是
- 计算机科学与技术影视,计算机科学与技术专业--水墨的影视艺术语言的研究
- ownCloud问题处理server replied 423 Locked to
- 第164篇,陌生人和贵人(扶摇生财思维)
- centos8调整分辨率
- 【Linux】gdb调试器的使用