lua编程之元表与元方法
一、 前言
lua是一种非常轻量的动态类型语言,在1993年由由Roberto Ierusalimschy、Waldemar Celes 和 Luiz Henrique de Figueiredo等人发明,lua的设计目标是轻便地嵌入宿主语言,增强系统的可扩展性和可定制性。lua的源码只有两万余行,非常精简小巧,在目前的脚本引擎中,lua的速度是最快的,这也是lua进入程序设计语言前20名,如今已经广泛应用于游戏行业,这几篇文章将会讨论下lua的几个比较重要的特性。
一门语言的类型系统是其最根本的特征,所以本文先从与lua的类型系统关系最紧密的元表和元方法谈起。作为一门轻量级语言,lua的核心非常精简,它的基本类型只有8种:nil,boolean,number,string,userdata,function,thread和table,其中table是唯一的数据结构,是lua中最重要的类型,可以作为其他数据结构的基础,如数组,链表,队列和集合等都可以通过table实现。更强大的是,lua还为table提供了自定义操作的功能。在c++等面向对象语言中,类的可操作行为由成员函数决定。lua中,元方法就是table的“成员函数”,为不同的table提供特殊的操作行为,元表是元方法的集合。通过元表和元方法,table可以直接实现类,继承等面向对象特性。
二、 元表元方法介绍
lua中每个值其实都有元表,不过每个table和userdata都可以有自己专有的元表,(userdata是宿主中的数据结构,可以使用宿主语言的方法,为了限制过度对其使用元表,不能在lua脚本中直接设置,需通过lua_setmetatable创建,这里不讨论),而其他类型的预定义操作都在一个共享的元表中,新的table默认没有元表,必须通过setmetatable和getmetatable设置和查询元表。
t = {}
assert(getmetatable(t)== nil)
t1 = {}
setmetatable(t, t1)
assert(getmetatable(t) == t1)
在元表中定义的函数就是元方法,table的元方法分为算数类,关系类,库定义和访问类的元方法。
1. 算数类元方法
lua的算数类元方法都有对应的字段名,包括__add, __mul,__sub, __div,__mod和__pow等,下面示例了如何定义两个table的加法操作,
a = { "a1", "a2","a3" }
b = { "b1", "b2", "b3" }
meta = { }
meta.__add = function(t1, t2)
t = { }
for k, v in ipairs(t1) do
table.insert(t, v)
end
for k, v in ipairs(t2) do
table.insert(t, v)
end
return t
end
setmetatable(a, meta)
c = a+b
for _,v in ipairs(c) do
print(v)
end
上面代码中只需要给表a设置了元表,表b没有元表也能正常运行,这与lua查找元表的顺序有关系。lua先查找第一个table,如果有元表并且其中有 __add方法就调用该方法,不关心第二个table有没有元表;否则查找第二个table有没有__add的元方法,有就调用第二个table的元方法;如果都没有这个元方法就引发一个错误。
2. 关系类元方法
关系类元方法只有等于__eq,小于__lt和小于等于__le这3个操作,其他3个会自动转化,如a>b会自动转为b<a.
a = { "a1", "a2" }
b = { "b1", "b2", "b3" }
meta = { }
meta.__le = function(a, b)
for k in pairs(a) do
if not b[k] then return false end
end
return true
end
meta.__lt = function(a, b)
return a<=b and not (b<=a)
end
meta.__eq = function(a, b)
return a<=b and b<=a
end
setmetatable(a, meta)
setmetatable(b, meta)
print(a<=b)
print(a<b)
print(a>=a)
print(b>a)
print(b<a)
与算法类元方法不同,table必须具有相同的元方法才能用于比较操作。
3. 库定义的元方法
上面的元方法都是lua核心具有的,是lua虚拟机定义的,除此之外,各种程序库也会用自己的字段定义元方法,比如print总是调用table的tostring方法,
a = { "a1", "a2" }
meta.__tostring = function(a)
local l = { }
for _,k in pairs(a) do
l[#l+] = k;
end
return "{"..table.concat(l, ",").."}"
end
setmetatable(a, meta)
print(a)
4. 访问类元方法
访问元方法使用最普遍的是__index和__newindex。一般当访问一个table中不存在的元素时会返回nil,但是如果table具有__index元方法,就不返回nil而是调用这个元方法。利用__index可以方便地实现继承,
mt = { }
mt.__index = function(t, k)
return base[k]
end
base = { b1 = , b2 = , b3 = }
derive = { d = }
setmetatable(derive, mt)
print(derive.b1)
print(derive.d)
当对table中不存在的索引赋值时就会调用__newindex元方法,
mt = { }
mt.__newindex = function(t, k, v)
base[k] = v
end
base = { b1 = , b2 = , b3 = }
derive = { d1 = }
setmetatable(derive, mt)
derive["d2"] =
print(base.d2)
三、 元表元方法实例
下面是一个使用元方法的实例,用于产生迭代递增表,
T = { container = { } }
T.mt = {
__add = function(a, b)
local c = T.new{}
for k,v in pairs(T.new(a)) do
c[k] = v
end
for k,v in pairs(T.new(b)) do
c[k] = v
end
return c
end,
__sub = function(a, b)
local c = T.new{}
for k,v in pairs(T.new(a)) do
c[k] = v
end
for k,v in pairs(T.new(b)) do
c[k] = nil
end
return c
end,
__tostring = function(a)
local l = { }
for k in pairs(a) do
l[#l+] = k;
end
return "{"..table.concat(l, ",").."}"
end
}
T.new = function(t)
if (t == nil) then t = {} end
if (getmetatable(t) == T.mt) then return t end
local r = {}
for _, b in ipairs(t) do
r[tostring(b)] = true
end
setmetatable(r, T.mt)
return r
end
T.print = function(t)
for k, v in pairs(t.container) do
print(k)
print(v)
end
end
local mt = {
__newindex = function(t, k, v)
t.container[k] = T.new(v)
end,
__index = function(t, k)
return t.container[k]
end,
}
setmetatable(T, mt)
T["first"] = { "a1", "b1"}
print("elements in table first")
T.print(T)
T["second"] = T["first"] + { "a2", "b2", "a3", "b3"}
print("elements in table first and second")
T.print(T)
T["third"] = T["second"] - { "a3", "b3" }
print("elements in table first, second and third")
T.print(T)
lua编程之元表与元方法的更多相关文章
- Lua中的元表与元方法学习总结
前言 元表对应的英文是metatable,元方法是metamethod.我们都知道,在C++中,两个类是无法直接相加的,但是,如果你重载了"+"符号,就可以进行类的加法运算.在Lu ...
- Lua中的元表与元方法
[前言] 元表对应的英文是metatable,元方法是metamethod.我们都知道,在C++中,两个类是无法直接相加的,但是,如果你重载了“+”符号,就可以进行类的加法运算.在Lua中也有这个道理 ...
- lua中 table 元表中元方法的重构实现
转载请标明出处http://www.cnblogs.com/zblade/ lua作为游戏的热更新首选的脚本,其优势不再过多的赘述.今天,我主要写一下如何重写lua中的元方法,通过自己的重写来实现对l ...
- Lua中的元表和元方法
Lua中每个值都可具有元表. 元表是普通的Lua表,定义了原始值在某些特定操作下的行为.你可通过在值的原表中设置特定的字段来改变作用于该值的操作的某些行为特征.例如,当数字值作为加法的操作数时,Lua ...
- Lua 学习笔记(十一)元表与元方法
在Lua中的每个值都有一套预定义的操作集合.例如可以将数字相加,可以连接字符串,还可以在table中插入一对key-value等.但是我们无法将两个table相加,无法对函数作比较,也无法调用一个字符 ...
- 【游戏开发】小白学Lua——从Lua查找表元素的过程看元表、元方法
引言 在上篇博客中,我们简单地学习了一下Lua的基本语法.其实在Lua中有一个还有一个叫元表的概念,不得不着重地探讨一下.元表在实际地开发中,也是会被极大程度地所使用到.本篇博客,就让我们从Lua查找 ...
- lua元表与元方法
lua中提供的元表(metatable)与元方法(metamethod)是一种非常重要的语法,metatable主要用于做一些类似于C++重载操作符式的功能. lua中提供的元表是用于帮助lua变量完 ...
- lua metatable和metamethod元表和元方法
Lua中提供的元表是用于帮助Lua数据变量完成某些非预定义功能的个性化行为,如两个table的相加.假设a和b都是table,通过元表可以定义如何计算表达式a+b.当Lua试图将两个table相加时, ...
- Step By Step(Lua元表与元方法)
Step By Step(Lua元表与元方法) Lua中提供的元表是用于帮助Lua数据变量完成某些非预定义功能的个性化行为,如两个table的相加.假设a和b都是table,通过元表可以定义如何计算表 ...
随机推荐
- SOA面向服务架构——SOA的概念
SOA的概念是Gartner 在1996年提出来的,并于2002年12月进一步提出SOA是“现代应用开发领域最重要的课题”. 一.SOA的定义 SOA分为广义的SOA和狭义的SOA,广义的SOA是 ...
- spring-boot默认的application.properties属性
# =================================================================== # COMMON SPRING BOOT PROPERTIE ...
- BZOJ1434:[ZJOI2009]染色游戏(博弈论)
Description 一共n×m个硬币,摆成n×m的长方形.dongdong和xixi玩一个游戏,每次可以选择一个连通块,并把其中的硬币全部翻转,但是需要满足存在一个硬币属于这个连通块并且所有其他硬 ...
- luogu【模板】三维偏序(陌上花开)
嘟嘟嘟 很显然我开始学\(CDQ\)分治了. 我刚开始学的时候看了一篇博客,上面全是一些抽象的概念,看完后真是一头雾水,最后还不得不抄了这题的代码. 但这样可不行呀-- 于是我就不打算再扣那篇博客,而 ...
- jQuery鼠标悬停
(function ($) { $.fn.hoverdir = function(options){ var options = $.extend({ choice : ".cove&quo ...
- ES6新特性5:类(Class)和继承(Extends)
本文摘自ECMAScript6入门,转载请注明出处. 一.类(Class) 1.基本语法 JavaScript语言的传统方法是通过构造函数,定义并生成新对象.下面是一个例子 function Poin ...
- [源码分析]ArrayList
add public boolean add(E e) { //先确保数组容量 ensureCapacityInternal(size + 1); //直接将值放在size位置 elementData ...
- package结构
1.package结构 一个package下常见的文件. 路径有:├── CMakeLists.txt #package的编译规则(必须)├── package.xml #package的描述信息(必 ...
- Kafka设计解析(十一)Kafka无消息丢失配置
转载自 huxihx,原文链接 Kafka无消息丢失配置 目录 一.Producer端二.Consumer端 Kafka到底会不会丢数据(data loss)? 通常不会,但有些情况下的确有可能会发生 ...
- JDK(八)JDK1.7&1.8源码对比分析【集合】HashMap
前言 在JDK1.8源码分析[集合]HashMap文章中,我们分析了HashMap在JDK1.8中新增的特性(引进了红黑树数据结构),但是为什么要进行这个优化呢?这篇文章我们通过对比JDK1.7和1. ...