Lua中的元表和元方法学习笔记

元表(metatable)是 Lua 里每种类型的值的默认操作方式的集合,例如,数字可以加减乘除、字符串可以连接合并、table 可以插入一对 key-value 值、函数可以被调用等等,这些操作都遵循其预定义的行为来执行。

而值的默认操作方式不是一成不变的,可以通过元表来修改其行为表现,或者是新定义一些默认没有的操作。例如,当两个 table 相加时, Lua 会检查它们之间的元表里是否有 "__add" 这个函数,如果定义有这个函数, 则调用这个函数来执行一次加法操作。

这里,相加这个操作的函数名 -- "__add" 是元表的键名(元表的键名也称之为事件(event),一般以 2 个下划线 "_" 开头),而 "__add" 函数则是这个相加操作的元方法(metamethod)。对于值的操作,Lua 都将其关联上一个被称作事件的指定健,当 Lua 需要对一个值发起这些操作中的一个时, 它会去检查值的元表里是否有对应事件。如果有,则键名对应的值(元方法)将控制 Lua 怎样去执行这个操作。

getmetatable - 获取元表

Lua 里每个值都有一个元表。table 类型和 userdata 类型的值可以有各自独立的元表,而其他类型的值则是公用其类型所预先定义的元表。例如,可以用 getmetatable 来获取一个字符串的元表:

代码如下:

a = "just a test"
print(getmetatable(a))

上面的操作会输出 "table: 0x7fa8614080f0" 的 table,里面包含着预先定义给字符串的操作方法,其内容结构如下:

代码如下:

-__index-sub [function: 0x7fee39408050]
        -upper [function: 0x7fee394080a0]
        -len [function: 0x7fee39407ec0]
        -gfind [function: 0x7fee39407e20]
        -rep [function: 0x7fee39407fb0]
        -find [function: 0x7fee39407d30]
        -match [function: 0x7fee39407f60]
        -char [function: 0x7fee39407c90]
        -dump [function: 0x7fee39407ce0]
        -gmatch [function: 0x7fee39407e20]
        -reverse [function: 0x7fee39408000]
        -byte [function: 0x7fee39407c40]
        -format [function: 0x7fee39407d80]
        -gsub [function: 0x7fee39407e70]
        -lower [function: 0x7fee39407f10]

Lua 在创建新的 table 时不会创建元表,因此想调用 getmetatable 函数获取其元表的话,只会返回一个 nil 值。

代码如下:

tbl = {}
print(getmetatable(tbl))

setmetatable - 修改元表

对于上面所说的新创建的 table 是空元表的问题,可以用 setmetatable 来修改其元表:

代码如下:

tbl = {}
t1 = {key = "val"}
setmetatable(tbl, t1)
print(getmetatable(tbl))

对于上面所说的 2 个 table 相加的情况,可以给 table 添加一个 __add 的元方法就可以进行相加操作:

代码如下:

t1 = {"a", "b", "c", "d"}
t2 = {5, 6, 7, 8, 9}
 
mt = {}
mt.__add = function(a, b)
    local tbl = {}
    local ret = {}
    for k, v in pairs(a) do tbl[v] = true end
    for k, v in pairs(b) do tbl[v] = true end
    for k, v in pairs(tbl) do
        table.insert(ret, k)
    end
    return ret
end
 
setmetatable(t1, mt)
setmetatable(t2, mt)
 
t = t1 + t2
for k, v in pairs(t) do print(v) end

(0)

相关推荐

  • Lua字符串库(string库)学习笔记

    Lua 最强大的特性之一就是它的字符串处理能力,它支持字符格式化输出,具有可扩展的模式匹配查找功能,以及一些实用的字符操作,例如查询.截取.替换和删除等字符串操作,这些字符串操作函数都封装在一个名为 string 的模块里. Lua 里的字符索引是从 1 开始,索引值也可以是负数,这种情况将被解释成向后索引,从字符串末尾开始算起. 下面是 Lua 5.2 提供的字符串操作函数: byte 函数 string.byte 把字符串里的第 i 个字符转为 ASCII编码,默认是输出第一个字符的编码(只

  • Lua 学习笔记之C API 遍历 Table实现代码

    Lua 通过一个虚拟栈与 C 的交互,正数索引自底向上取值,负数索引自顶向下取值. Lua 中的 Table(表)结构可以使用任何数据作为 key 进行取值.使用 C API 访问 Table 中的元素有两种方法: 复制代码 代码如下: lua_getglobal(L, t); lua_pushinteger(L, k); -- 这里可以换成其它类型的 lua_pushXXXX(L, k) 压数据到栈顶作key lua_gettable(L, -2); lua_getglobal(L, t);

  • Lua中的闭包学习笔记

    之前介绍 Lua 的数据类型时,也提到过,Lua 的函数是一种"第一类值(First-Class Value)".它可以: 存储在变量或 table (例如模块和面向对象的实现)里 复制代码 代码如下: t = { p = print } t.p("just a test!") 作为实参(也称其为"高阶函数(higher-order function)")传递给其他函数调用 复制代码 代码如下: t = {2, 3, 1, 5, 4} table

  • Lua基础教程之赋值语句、表达式、流程控制、函数学习笔记

    赋值语句 注释,单行用(--)来表示:多行用(--[[ ... ]])来标示: 定义,lua中没有定义(申明数据类型),它是通过赋值来确定其数据类型的. 赋值,是改变一个变量的值和改变表域的最基本的方法. a = "hello" .. "world" Lua可以对多个变量同时赋值,变量列表和值列表的各个元素用逗号分开,赋值语句右边的值会依次赋给左边的变量.a, b = 10, 2*x <--> a=10; b=2*x 遇到赋值语句Lua会先计算右边所有的

  • Lua入门学习笔记

    最近在使用Cocos2d-x + Lua来开发游戏. 游戏的主要逻辑将在Lua里写,之前没有接触过Lua,以下是我总结的入门笔记. 运算符 逻辑运算符 与:and 或:or 非:not 逻辑判断只有在false和nil时为假,其余均为真. or和and会返回第一个断路的值. Lua中没有C语言的三元符(x ? a : b),但有一个替代方案(x and a) or b. 需要注意的是,以上方案在x为true,a为false,b为true的情况下与三元符的结果是相反的. 关系运算符 不等于:~=

  • Lua学习笔记之类型与值

    基础介绍 Lua是一种动态类型的语言.在语言中没有类型定义的语法,每个值都带有其自身的类型信息.在Lua中有8种基本类型,分别是: nil(空)类型 boolean(布尔)类型 number(数字)类型 string(字符串)类型 userdata(自定义类型) function(函数)类型 thread(线程)类型 table(表)类型 以上是Lua中的8中基本类型,我们可以使用type函数,判断一个值得类型,type函数返回一个对应类型的字符串描述.例如: local iValue = 10

  • Lua表达式和控制结构学习笔记

    算术操作符 Lua 的算术操作符有: "+"(加法): 复制代码 代码如下: print(1 + 2) "-"(减法): 复制代码 代码如下: print(2 - 1) "*"(乘法): 复制代码 代码如下: print(1 * 2) "/"(除法): 复制代码 代码如下: print(1 / 2) "^"(指数): 复制代码 代码如下: print(27^(-1/3)) "%"(取模)

  • Lua模块与包学习笔记

    从 Lua 5.1 开始,Lua 加入了标准的模块管理机制,可以把一些公用的代码放在一个文件里,以API 接口的形式在其他地方调用,有利于代码的重用和降低代码耦合度. 创建模块 其实 Lua 的模块是由变量.函数等已知元素组成的 table,因此创建一个模块很简单,就是创建一个 table,然后把需要导出的常量.函数放入其中,最后返回这个 table 就行.格式如下: 复制代码 代码如下: -- 定义一个名为 module 的模块 module = {}   -- 定义一个常量 module.c

  • Lua基础教程之表(Table)学习笔记

    表 复制代码 代码如下: a = { }     b = { x = 1, ["hello, "] = "world!" }     a.astring = "ni, hao!"     a[1] = 100     a["a table"] = b     function foo()     end     function bar()     end     a[foo] = bar     --分别穷举表a和b    

  • Lua面向对象编程学习笔记

    其实 Lua 中的 table 是一种对象,因为它跟对象一样,有其自己的操作方法: 复制代码 代码如下: Role = { hp = 100 } function Role.addHp(hp)     Role.hp = Role.hp + hp end   Role.addHp(50) print(Role.hp) 上面代码创建了一个名为 Role 对象,并有一个 addHp 的方法,执行 "Role.addHp" 便可调用 addHp 方法. 不过上面对象 Role 是以全局变量的

  • Lua学习笔记之数据类型

    从本篇博客开始研究一下Lua,现在的Lua真得是很火,因为Cocos2d-x写游戏的时候会用到,所以就拿过来学学吧,先从基础的语法开始,然后慢慢的深入.本人也是刚刚学习,希望和学习Lua的大家交流,博客权当笔记,有错误之处还请赐教. 当然首先是开发环境了,我的学习背景是Cocos2d-x,所以下载了最近发布的Cocos Code IDE版本,我们可以在Cocos Code IDE上边新建工程,然后写Lua测试代码,关于Cocos Code IDE的使用官方有不少的教程,这里就不说了.当然你也可以

  • Lua学习笔记之运算符和表达式

    本篇博客学习一下Lua的运算符,比较简单,我将说明直接写到了代码中,代码如下. --算术运算符 --二元运算符:+ - * / ^ (加减乘除幂) --一元运算符:- (负值) --这些运算符的操作数都是实数,Lua中没有自增自减的运算符. --关系运算符 -- < > <= >= == ~= --这里需要注意的是不等于是用~=表示的 --这些操作符返回结果为false或者true:==和~=比较两个值,如果两个值类型不同,Lua认为两者不同: --nil只和自己相等.Lua通过引

  • Lua学习笔记之数据结构

    最近研究Lua,顺便写点笔记吧!数据结构是没有语言之分的,只不过不同的语言实现起来的语法不同,既然是Lua菜鸟,就来实现几个常用的数据结构来练练语法吧!首先是作为数据结构基石的数组,在Lua中数组是用表来实现的,表是个强大的东西,能表示太多东西了,当表中元素的下标都是整数的时候,我们把这个表称作数组.数组的大小不固定,可以动态的增长. 复制代码 代码如下: --创建一个简单的数组 local arr1 = {1,2,3,4,5,6} --遍历数组中得每一个元素 for i,v in ipairs

  • Lua学习笔记之表和函数

    Lua中的表和函数比较重要,正是因为二者的结合才完成了很多很多的功能,Lua才变得如此的强大,所以有必要仔细的学习一下表和函数.如下的代码体现了表的用法. --表 --可以使用构造器来初始化表,表是Lua特有的功能强大的东西.最简单的构造函数是{},用来创建一个空表. local days = {"xiao", "ta", "hello", "lua"} --第一个元素索引为1,以后的类推,这一点和其他语言的第一个元素索引是0

  • Lua中的table学习笔记

    table 在 Lua 里是一种重要的数据结构,它可以说是其他数据结构的基础,通常的数组.记录.线性表.队列.集合等数据结构都可以用 table 来表示,甚至连全局变量(_G).模块.元表(metatable)等这些重要的 Lua 元素都是 table 的结构.可以说,table  是一个强大而又神奇的东西. table 特性 在之前介绍 Lua 数据类型时,也说过了 table 的一些特性,简单列举如下(详情可查看之前的介绍): 1.table是一个"关联数组",数组的索引可以是数字

随机推荐