Lua中的元表和元方法
Lua中每个值都可具有元表。 元表是普通的Lua表,定义了原始值在某些特定操作下的行为。你可通过在值的原表中设置特定的字段来改变作用于该值的操作的某些行为特征。例如,当数字值作为加法的操作数时,Lua检查其元表中的"__add"字段是否有个函数。如果有,Lua调用它执行加法。
我们称元表中的键为事件(event),称值为元方法(metamethod)。前述例子中的事件是"add",元方法是执行加法的函数。
可通过函数getmetatable查询任何值的元表。
可通过函数setmetatable替换表的元表。不能从Lua中改变其他类型的元表(除了使用调试库);必须使用C API才能做到。
表和完整的用户数据具有独立的元表(尽管多个表和用户数据可共享元表);每种其他类型的所有值共享一个元表。所以,所有数字共享一个元表,字符串也是,等等。
元表可以控制对象的数学运算、顺序比较、连接、取长、和索引操作的行为。元表也能定义用户数据被垃圾收集时调用的函数。Lua给这些操作的每一个都关联了称为事件的特定键。当Lua对某值执行其中一个操作时,检查该值是否含有元表以及相应的事件。如果有,与该键关联的值(元方法)控制Lua如何完成操作。
元表控制后面列举的操作。每个操作由相应的名字标识。每个操作的键是由其名字前缀两个下划线“__”的字符串;例如,操作“加(add)”的键是字符串"__add"。这些操作的语义通过一个Lua函数描述解释器如何执行操作作了更好的说明。
下面显示的Lua代码只是说明性的;真实的行为被硬编码到解释器中,并且比这里的模拟更加高效。这些描述中的所有函数(rawget、tonumber等等。)在§5.1中描述。特别一提,要获取给定对象的元方法,我们使用表达式
metatable(obj)[event]
它应被解读为
rawget(getmetatable(obj) or {}, event)
就是说,访问一个元方法不会调用其他元方法,而且访问没有元表的对象不会失败(只是结果为nil)。
"add": + 操作。
下面的getbinhandler函数定义Lua如何选择二元操作的处理程序。首先尝试第一操作数,如果它的类型没有定义该操作的处理程序,则尝试第二操作数。
function getbinhandler (op1, op2, event)
return metatable(op1)[event] or metatable(op2)[event]
end
通过应用该函数,op1 + op2的行为是
function add_event (op1, op2)
local o1, o2 = tonumber(op1), tonumber(op2)
if o1 and o2 then -- 两操作数都是数字
return o1 + o2 -- ‘+’此处是‘add’的原语
else -- 至少一个操作数不是数字
local h = getbinhandler(op1, op2, "__add")
if h then -- 用两个操作数调用处理程序
return (h(op1, op2))
else -- 没有可用的处理程序:缺省行为
error(...)
end
end
end
"sub": - 操作。 行为类似于“add”操作。
"mul": * 操作。 行为类似于“add”操作。
"div": / 操作。 行为类似于“add”操作。
"mod": % 操作。 行为类似于“add”操作。以o1 - floor(o1/o2)*o2为操作原语。
"pow": ^ (取幂)操作。 行为类似于“add”操作,以函数pow(来自C数学库)为操作原语。
"unm": 一元-操作。
function unm_event (op)
local o = tonumber(op)
if o then -- 操作数是数字?
return -o -- ‘-’此处是‘unm’的原语
else -- 操作数不是数字
-- 尝试由操作数取得处理程序。
local h = metatable(op).__unm
if h then-- 用操作数调用处理程序
return (h(op))
else -- 没有可用的处理程序:缺省行为
error(...)
end
end
end
"concat": .. (连接)操作。
function concat_event (op1, op2)
if (type(op1) == "string" or type(op1) == "number") and
(type(op2) == "string" or type(op2) == "number") then
return op1 .. op2 -- 字符串连接原语
else
local h = getbinhandler(op1, op2, "__concat")
if h then
return (h(op1, op2))
else
error(...)
end
end
end
"len": # 操作。
function len_event (op)
if type(op) == "string" then
return strlen(op) -- 取字符串长度原语
elseif type(op) == "table" then
return #op -- 取表长度原语
else
local h = metatable(op).__len
if h then -- 用操作数调用处理程序
return (h(op))
else -- 没有可用的处理程序:缺省行为
error(...)
end
end
end
"eq": == 操作。 函数getcomphandler定义Lua如何选择比较操作符的元方法。只有待比较的两个对象类型和选定操作对应的元方法都相同,才会选择该元方法。
function getcomphandler (op1, op2, event)
if type(op1) ~= type(op2) then return nil end
local mm1 = metatable(op1)[event]
local mm2 = metatable(op2)[event]
if mm1 == mm2 then
return mm1
else
return nil
end
end
"eq"事件定义如下:
function eq_event (op1, op2)
if type(op1) ~= type(op2) then -- 类型不同?
return false -- 对象不同
end
if op1 == op2 then -- 相等原语?
return true -- 对象相同
end -- 尝试元方法
local h = getcomphandler(op1, op2, "__eq")
if h then
return (h(op1, op2))
else
return false
end
end
a ~= b等价于not (a == b)。
"lt": < 操作。
function lt_event (op1, op2)
if type(op1) == "number" and type(op2) == "number" then
return op1 < op2 -- 数字比较
elseif type(op1) == "string" and type(op2) == "string" then
return op1 < op2 -- 词典顺序比较
else
local h = getcomphandler(op1, op2, "__lt")
if h then
return (h(op1, op2))
else
error(...);
end
end
end
a > b等价于b < a。
"le": <= 操作。
function le_event (op1, op2)
if type(op1) == "number" and type(op2) == "number" then
return op1 <= op2 -- 数字比较
elseif type(op1) == "string" and type(op2) == "string" then
return op1 <= op2 -- 词典顺序比较
else
local h = getcomphandler(op1, op2, "__le")
if h then
return (h(op1, op2))
else
h = getcomphandler(op1, op2, "__lt")
if h then
return not h(op2, op1)
else
error(...);
end
end
end
end
a >= b等价于 b <= a。注意,假定a <= b等价于not (b < a),那么当没有“le”元方法时,Lua尝试“lt”。
"index": 索引访问table[key]。
function gettable_event (table, key)
local h
if type(table) == "table" then
local v = rawget(table, key)
if v ~= nil then
return v
end
h = metatable(table).__index
if h == nil then
return nil
end
else
h = metatable(table).__index
if h == nil then
error(...);
end
end
if type(h) == "function" then
return (h(table, key)) -- 调用处理程序
else
return h[key] -- 对它重复上述操作
end
end
"newindex": 索引赋值table[key] = value。
function settable_event (table, key, value)
local h
if type(table) == "table" then
local v = rawget(table, key)
if v ~= nil then
rawset(table, key, value);
return
end
h = metatable(table).__newindex
if h == nil then
rawset(table, key, value);
return
end
else
h = metatable(table).__newindex
if h == nil then
error(...);
end
end
if type(h) == "function" then
h(table, key,value) -- 调用处理程序
else
h[key] = value -- 对它重复上述操作
end
end
"call": 当Lua调用值时被调用。
function function_event (func, ...)
if type(func) == "function" then
return func(...) -- 调用原语
else
local h = metatable(func).__call
if h then
return h(func, ...)
else
error(...)
end
end
end
相关推荐
### Lua中的元表和元方法使用详解 #### 一、元表的概念与作用 在Lua中,元表是一种特殊的表,它可以用来控制另一个表的行为。简单来说,元表定义了一系列特殊的方法,这些方法称为元方法,用于重写或扩展表的操作...
《Excel到Lua转表工具详解》 在编程领域,数据管理是至关重要的环节,而Excel作为数据处理的常用工具,其灵活性和易用性深受广大用户的喜爱。然而,在游戏开发或者自动化脚本编写中,我们可能需要将Excel的数据转换...
元表允许我们为任何值(包括表、字符串、数字等)添加元方法,这些元方法在特定操作下会被调用,从而实现类、继承和多态等概念。本教程“Lua中利用元表实现类和多态教程共28页”深入探讨了如何巧妙运用元表来构建...
此外,还有关于元表和元方法的概念,这是Lua实现面向对象编程的关键,它允许你自定义对象的行为。 "lua-5.1中文手册.chm"则是一个详细的参考文档,覆盖了Lua 5.1的所有内置函数、库和API。你可以在这里查找关于字符...
Lua的table元表自我学习笔记分享。--lua元表总结 --1、__index的运用 (调用table的一个不存在的索引时,会使用到元表的__index元方法,搜索元表是否也有改索引,__index可以是一个函数也可是一个table。)
这种模拟方法是基于表(table)和元表(metatable)的概念,以及一些特殊函数来实现的。在 Lua 中,类可以被看作是一个包含数据和方法的表,而对象则是类的一个实例。接下来,我们将深入探讨 Lua 中的类、继承以及...
例如,如果你定义了一个表的 __add 元方法,那么当你尝试将两个这样的表相加时,Lua 将会执行这个元方法。 接着,我们来看 Lua 的基本函数库。这个库提供了许多内置的函数,帮助我们进行基本的数学运算、字符串处理...
4. **元表和元方法**:LUA通过元表实现了动态类型的行为定制,例如自定义算术操作符的行为。元方法是与特定操作符关联的函数,通过元表调用。 5. **模块系统**:LUA没有内置的模块系统,但可以通过全局变量和...
8. **元表和元方法**:Lua的表支持元表和元方法的概念,这使得表的行为可以根据其元表进行定制,如自定义索引和更新操作。 9. **C API**:Lua提供了一个C语言的接口,允许开发者用C语言编写扩展模块,从而与C/C++...
游戏公司可能使用自定义的加密方法来保护其lua脚本,防止被玩家篡改或获取敏感信息。而lua反编译工具则为逆向工程师提供了手段,让他们能探索游戏的内部逻辑,这对于mod制作、漏洞挖掘和游戏研究都有所帮助。 总之...
5. **元表与元方法**:LUA支持元表机制,元表可以定义对象的操作行为,如索引、长度等。元方法是通过元表调用的特殊方法,例如,当尝试访问不存在的表字段时,会触发__index元方法。 6. **垃圾回收**:LUA自动进行...
lua学习 相关函数库和学习参考资料。 包括:lua4.0函数库 lua5.2API函数 lua-table函数库 lua捕获 lua基本函数库 lua模式匹配 lua数学库 lua文件处理 ...lua元表和元方法 string库函数 简单C访问lua
它允许程序员通过设置不同的元方法来扩展或修改表的行为,从而使得Lua语言变得更加灵活和强大。例如,可以通过元表来实现表之间的继承关系,或者自定义表中的操作符行为等。 ## 二、元表的基本操作 ### 1. 创建元...
2. **元表和元方法**:Lua中的元表是实现元编程的关键,允许你为特定类型的值定义特殊的行为。比如,你可以为表格设置一个元表,使其支持算术操作,如加法或乘法。元方法是与元表关联的函数,当调用特定操作符时会被...
"安装羽扇如果您正在使用 ,请运行: luarocks install emoji手动的将文件夹复制到您的Lua解释器可以找到并需要它的位置: local emoji = require ( ' emoji ' )界面方法emoji.get emoji. get ( " tea " ) -> " :...
1. **元表变化**:Lua 5.2的元表设计更加灵活,允许在元表中直接使用数字键,这意味着你可以为特定的数值操作设置元方法,增强了元表的功能性。 2. **字符串字面量改变**:字符串字面量现在可以使用八进制和十六进制...
5. **元表和元方法**:Lua支持元表和元方法的概念,这使得在实现面向对象编程时具有很高的灵活性,可以方便地创建自定义行为。 6. **强大的表数据结构**:Lua的表不仅可以用来存储数组,还可以用作关联数组、集合、...
总之,`jsonToLua.py`提供了一种方便的方法,帮助开发者在JSON和Lua Table之间进行数据转换,简化了跨语言数据交互的过程。理解JSON和Lua Table的基本概念,以及如何利用Python来处理它们,对于进行多语言开发的...
4. **元编程**:Lua通过Metatables提供了一种灵活的元编程机制,可以改变基本操作的行为,如__add、__mul等元方法。 5. **环境变量与全局环境**:Lua的全局环境是一个特殊的表,所有未在特定环境中定义的变量都存储...
由于其动态特性和弱类型,表是Lua的核心特性之一。优化表的关键在于减少内存占用和提高访问效率。 2. 内存优化:当多个脚本或对象中存在大量重复的表时,内存消耗会显著增加。通过提取公共部分,创建共享的“原型”...