lua元表以及元方法

2023-11-16

lua元表以及元方法

lua中的变量是没有数据类型的,值有类型。类型有八种nil,number,boolean, string, function, thread, userdata以及table。

Lua 中的每个值都可以有一个 元表 。 这个 元表 就是一个普通的 Lua 表,它用于定义原始值在特定操作下的行为。例如,当你对非数字值做加操作时, Lua 会检查该值的元表中的 "__add" 域下的函数。 如果能找到,Lua 则调用这个函数来完成加这个操作。

元表中的键对应着不同的 事件 名; 键关联的那些值被称为 元方法 。 在上面那个例子中引用的事件为 "add" , 完成加操作的那个函数就是元方法。

可以用 getmetatable 函数 来获取任何值的元表。

使用 setmetatable 来替换一张表的元表。在 Lua 中,你不可以改变表以外其它类型的值的元表 (除非你使用调试库); 若想改变这些非表类型的值的元表,请使用 C API.

 接下来会给出一张元表可以控制的事件的完整列表。 每个操作都用对应的事件名来区分。 每个事件的键名用加有 '__' 前缀的字符串来表示; 例如:"add" 操作的键名为字符串 "__add"。

 "add": + 操作。 如果任何不是数字的值(包括不能转换为数字的字符串)做加法, Lua 就会尝试调用元方法。 首先、Lua 检查第一个操作数(即使它是合法的), 如果这个操作数没有为 "__add" 事件定义元方法, Lua 就会接着检查第二个操作数。 一旦 Lua 找到了元方法, 它将把两个操作数作为参数传入元方法, 元方法的结果(调整为单个值)作为这个操作的结果。 如果找不到元方法,将抛出一个错误。
"sub": - 操作。 行为和 "add" 操作类似。
"mul": * 操作。 行为和 "add" 操作类似。
"div": / 操作。 行为和 "add" 操作类似。
"mod": % 操作。 行为和 "add" 操作类似。
"pow": ^ (次方)操作。 行为和 "add" 操作类似。
"unm": - (取负)操作。 行为和 "add" 操作类似。
"idiv": // (向下取整除法)操作。 行为和 "add" 操作类似。
"band": & (按位与)操作。 行为和 "add" 操作类似, 不同的是 Lua会在任何一个操作数无法转换为整数时尝试取元方法。
"bor": | (按位或)操作。 行为和 "band" 操作类似。
"bxor": ~ (按位异或)操作。 行为和 "band" 操作类似 
"bnot": ~ (按位非)操作。 行为和 "band" 操作类似。
"shl": << (左移)操作。 行为和 "band" 操作类似。
"shr": >> (右移)操作。 行为和 "band" 操作类似。
"concat": .. (连接)操作。 行为和 "add" 操作类似, 不同的是 Lua在任何操作数即不是一个字符串 也不是数字(数字总能转换为对应的字符串)的情况下尝试元方法。
"len": # (取长度)操作。 如果对象不是字符串,Lua 会尝试它的元方法。 如果有元方法,则调用它并将对象以参数形式传入, 而返回值(被调整为单个)则作为结果。 如果对象是一张表且没有元方法,Lua 使用表的取长度操作。 其它情况,均抛出错误。
"eq": == (等于)操作。 和 "add" 操作行为类似, 不同的是 Lua 仅在两个值都是表或都是完全用户数据 且它们不是同一个对象时才尝试元方法。 调用的结果总会被转换为布尔量。
"lt": < (小于)操作。 和 "add" 操作行为类似, 不同的是 Lua 仅在两个值不全为整数也不全为字符串时才尝试元方法。 调用的结果总会被转换为布尔量。
"le": <= (小于等于)操作。 和其它操作不同, 小于等于操作可能用到两个不同的事件。 首先,像 "lt" 操作的行为那样,Lua 在两个操作数中查找 "__le" 元方法。 如果一个元方法都找不到,就会再次查找 "__lt" 事件, 它会假设 a <= b 等价于 not (b < a)。 而其它比较操作符类似,其结果会被转换为布尔量。

上面的这些元方法原理上都可以归为一类,我们举个例子来看:

local mt = {}

mt.__add = function(a,b)
    return a.v + b.v/2
end

local a = {v = 10}
local b = {v = 12}

setmetatable(a, mt)

print("a + b :", a + b)

 运行结果如下:

相当于重载了“+”号。


"index": 索引 table[key]。 当 table 不是表或是表 table 中不存在key 这个键时,这个事件被触发。 此时,会读出 table 相应的元方法。尽管名字取成这样, 这个事件的元方法其实可以是一个函数也可以是一张表。 如果它是一个函数,则以 table 和 key 作为参数调用它。如果它是一张表,最终的结果就是以 key 取索引这张表的结果。(这个索引过程是走常规的流程,而不是直接索引, 所以这次索引有可能引发另一次元方法。

"newindex": 索引赋值 table[key] = value 。 和索引事件类似,它发生在 table 不是表或是表 table 中不存在 key 这个键的时候。 此时,会读出 table 相应的元方法。同索引过程那样, 这个事件的元方法即可以是函数,也可以是一张表。 如果是一个函数, 则以 table、 key、以及 value 为参数传入。如果是一张表, Lua 对这张表做索引赋值操作。 (这个索引过程是走常规的流程,而不是直接索引赋值, 所以这次索引赋值有可能引发另一次元方法。)一旦有了 "newindex" 元方法, Lua 就不再做最初的赋值操作。(如果有必要,在元方法内部可以调用 rawset 来做赋值。

通过一个例子来说明其原理:

local mt = {}
mt.__index = function(t, k)
    print("call index function")
end

mt.__newindex = function(t,k,v)
    print("call new index function")
end

local t = {}
setmetatable(t, mt)

local temp = t.a
t.a = 10

输出如下:

也就是说,当调用表"t"中的元素"a",却在表"t"中找不到"a"的时候,会把“t”,“a”做为参数来调用“__index”函数。

当赋值表"t"中的元素"a",却在表"t"中找不到"a"的时候,会把“t”,“a”,value做为参数来调用“__newindex”函数。


"call": 函数调用操作 func(args)。 当 Lua 尝试调用一个非函数的值的时候会触发这个事件 (即 func 不是一个函数)。 查找 func 的元方法, 如果找得到,就调用这个元方法, func 作为第一个参数传入,原来调用的参数(args)后依次排在后面。

通过一个例子来说明其原理:

local mt = {}
mt.__call = function(f,...)
    print("call table like a function", f ,...)
end

local temp = {}
setmetatable(temp, mt)

temp(1,2,3)

输出如下:

相当于把函数调用赋予到了一个非函数类型。

这个元方法比较实用。可以把事件改变成表,可以事先赋予事件上值。还可以当成一个类的构造函数实使用。

 

此外还有一些元方法,书中并没有归类到这些事件里面。我做了一些统计

"mode":弱表属性,赋予一张表弱引用属性。(弱表比较有趣,下一篇文章会做说明)

"gc":在对象被GC的时候,会先调用元表里面的“gc”域。

"tostring":当调用tostring(obj)的时候,会先查找obj的元方法中的__tostring,如果有就调用,没有就会打印obj的内存位置。比如说上面的

 "pairs":迭代器的元方法,在执行pairs(t)的时候,会先找表t的元方法“__pairs”,如果有就以t为参数调用他,如果没有,就返回三个值next函数, t已经nil。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

lua元表以及元方法 的相关文章

  • 用于数据存储的 Lua 与 XML

    我们中的许多人都被灌输了使用 XML 来存储数据的观念 它的优点和缺点众所周知 我当然不想在这里讨论它们 然而 在我用 C 编写的项目中 我也使用 Lua 我非常惊讶 Lua 能够如此出色地存储和处理数据 然而 Lua 的这一方面却鲜为人知
  • 代码说“尝试比较数字<=实例”

    It says Players ninjafox56 PlayerGui Shop ShopGui LightSide ChooseSideL 5 尝试比较数字 Rank game Players LocalPlayer leadersta
  • Lua中运算符~=是什么意思?

    什么是 Lua中的运算符是什么意思 例如 在以下代码中 if x params then the is not equals 这在其他语言中是等价的
  • 访问 Lua 类型元表

    显然 getmetatable 可以访问几种类型的元表 getmetatable getmetatable getmetatable newproxy true 然而 似乎您无法获取其他类型的元表 除了函数 似乎无法访问数字 布尔值或 ni
  • 如何使用循环将字符串连接成一个?

    有人可以帮我解决字符串连接问题吗 我从寄存器读取数据 它的函数 utf regAddr length 我得到带有十进制数字的表格 然后将其转换为十六进制并循环字符串 我需要将这些字符串连接成一个 Lua中没有像 这样的操作符 functio
  • Corona/Box2D 检测与非移动静态物体的碰撞

    出于发帖原因 这是我正在尝试做的事情的简单版本 在屏幕上我有一个简单的圆形对象 它是静态的并且不会移动 然后用户可以拖放一条直线 如果该线穿过该圆圈 我希望触发碰撞事件 看来除非其中一个物体正在移动 否则永远不会检测到碰撞 绘制线条时能否检
  • 如何在多个Lua State(多线程)之间传递数据?

    我在中启动Redis连接池redis lua 通过从 C 调用 我得到了redis lua state 此 Lua 状态全局启动一次 仅在其他线程中启动get从中 当有一个 HTTP 请求 工作线程 时 我需要从redis lua stat
  • 了解静态链接嵌入式lua环境中lua扩展dll的构建/加载

    我有一个相对复杂的 lua 环境 我试图了解以下内容如何工作 起始设置包括以下两个模块 主要应用 无lua环境 DLL 静态链接到lua lib 包括解释器 该 dll 被加载到主应用程序中 并运行 lua 控制台解释器和可从控制台访问的
  • 如何解密Lua字节码?

    早上好 我正在尝试破译 Moon 字节码 但我无法以任何方式 有人可以帮助我吗 我有这个 例如 code 27 76 117 97 81 0 1 4 4 4 8 0 如何将此字节码解密为文本 我已经在这里搜索 http www asciit
  • 检查lua中是否存在目录?

    如何检查 lua 中是否存在目录 如果可能的话最好不使用 LuaFileSystem 模块 尝试做类似以下 python 行的事情 os path isdir path 这是一种在 Unix 和 Windows 上都适用的方式 无需任何外部
  • 如何在aerospike中获取ttl为-1的记录集?

    我在aerospike中有很多记录 我想获取ttl为 1的记录 请提供解决方案 只是为了澄清 设置TTL 为 1 https github com aerospike aerospike client go blob master docs
  • Kong - 验证上游 ssl(ssl_proxy 打开)

    我已经成功为 API 安装了 kong 网关 该 API 通过上游负载平衡到多个目标 应用程序服务器 现在 我有一个我的应用程序服务器的自签名证书 kong 和目标之间的 ssl 握手应该失败 我推断 kong 不验证上游证书 经过一些研究
  • 尝试将 nil 与数字堆栈回溯进行比较?

    我正在通过以下链接玩 Lua https www lua org pil 4 2 html https www lua org pil 4 2 html并对某一点感到困惑 Lua 5 2 4 Copyright C 1994 2015 Lu
  • 为什么 LuaJIT 这么好?

    编辑 不幸的是 LuaJIT 已从下面链接的比较中删除 This 比较 http shootout alioth debian org u64 which programming languages are fastest php编程语言的
  • Openresty 中的并发模型是什么?

    我很难理解 openresty 或 nginx 的并发模型 我读了Lua变量作用域 http wiki nginx org HttpLuaModule Lua Variable Scope 它解释了变量的生命周期 但它没有说明对它们的并发访
  • Lua 访问表的键和值

    我想在关卡编辑器中读取 Lua 文件 这样我就可以以可视化格式显示其数据供用户编辑 如果我有一个像这样的 Lua 表 properties Speed 10 TurnSpeed 5 Speed显然是关键并且10价值 我知道如果我知道像这样的
  • 关闭 Löve2D 中的抗锯齿功能

    我在用着L ve2D http love2d org用于编写一个小游戏 L ve2D 是 Lua 的开源游戏引擎 我遇到的问题是 当您在非整数位置绘制精灵时 某些抗锯齿过滤器会自动应用于精灵 love graphics draw sprit
  • 在 Awesome-wm 中为特定应用程序设置窗口布局

    如何配置很棒 以便它可以启动两个窗口对齐的新应用程序 如下所示 xxxxxxxxxx xxxxxxxxxx xxxxxxxxxx xxxxxxxxxx 其中 x 是 pidgin 中的对话窗口 是好友列表窗口 一般来说 我想指定右窗口的宽度
  • Lua中有状态迭代器和无状态迭代器的区别

    Lua中无状态和有状态迭代器有什么区别 请详细解释一下 什么时候需要使用无状态 什么时候需要使用另一种 我需要例子来理解这个概念 首先让我们就一个定义达成一致 在 Lua 中 迭代器是function 类似对象 每次调用时都会返回序列中的下
  • 推送 Lua 表

    我已经创建了一个Lua表C 但我不知道如何将该表推入堆栈顶部 以便我可以将其传递给 Lua 函数 有谁知道如何做到这一点 这是我当前的代码 lua createtable state libraries size 0 int table i

随机推荐

  • javaWeb项目中分页和模糊查询技术

    分页 需求 登录成功后 展现全部时 出现分页 思路 前端 1 设置分页按钮 以及分页数据 页码 总页数 总条数 2 设置分页请求 即点击上一页 下一页时发请求 后端 3 web xml映射 映射到Servlet能接收请求 4 Dao查询分页
  • opencv实践项目-人脸检测

    目录 1 opencv CascadeClassifier人脸检测步骤 2 CascadeClassifier分类器简介 2 1 从文件中加载级联分类器 2 2 目标检测方法 3 代码实现 1 opencv CascadeClassifie
  • SRVE0255E: A WebGroup/Virtual Host to handle /p2pd/servlet/dispatch has not been defined.

    Technote troubleshooting Problem Abstract When setting up IBM Cognos within IBM WebSphere the URI is not accessible The
  • 【MySQL】轻松学习 普通索引

    目录 引言 一 普通索引的创建 1 创建表时定义索引 2 已存在的表上创建索引 3 ALTER TABLE 语句创建索引 二 查看索引执行情况 引言 创建索引是指在某个表的一列或多列上建立一个索引 以便提高对表的访问速度 创建索引有3种方式
  • umijs----路由(修改路由的某一个path )

    1 在src下创建app js ts tsx 2 修改路由 export function patchRoutes routes routes为 umirc ts中设置的routes数组 可以使用数组的方法插入删除 运行时在最前面插入一个路
  • Webpack配置Vue热更新

    Webpack配置Vue热更新 需要的包 cnpm i vue webpack webpack cli webpack dev server html webpack plugin clean webpack plugin style lo
  • 【正点原子MP157连载】第七章 认识HAL库-摘自【正点原子】STM32MP1 M4裸机CubeIDE开发指南

    1 实验平台 正点原子STM32MP157开发板 2 购买链接 https item taobao com item htm id 629270721801 3 全套实验源码 手册 视频下载地址 http www openedv com t
  • selenium4

    1 单选框和复选框 单选框 type radio 定位 gt 点击 判断是否被选中 元素 is selected 复选框 type checkbox 只选择一个 gt 同单选框一样 全选 定位所有复选框 遍历 判断是否被选中 点击 选择部分
  • java入门六:java基础终章

    1 static关键字 静态变量和类一起加载 final修饰后的类无法被继承 2 抽象类 abstract修饰符可以用来修饰方法也可以修饰类 如果修饰方法 那么该方法就是抽象方法 如果修饰类 那么该类就是抽象类 抽象类中可以没有抽象方法 但
  • Linux Shell程序设计(2)

    实验十一 Shell程序设计 2 一 实验要求 综合运用shell编程知识进行设计性编程 二 实验内容和实验步骤 1 实验内容 假设你作为某工厂生产管理员 需要负责统计各车间每天生产的产品数据 你的计算机安装了双硬盘 为了保证数据安全 你在
  • 【定位问题】Mybatis-plus的selectPage()分页查询不生效问题

    背景 项目需要从mybits切换到mubits plus 但是我在进行分页查询的时候 发现一直不生效 问题原因 添加监听器 配置如下 Configuration MapperScan com baomidou mybatisplus sam
  • parted创建硬盘分区并创建LVM

    目的 将两个三T的硬盘做成LVM sdc sdd 一 parted将硬盘进行分区 1 parted的命令方式 Parted 命令分为两种模式 命令行模式和交互模式 1 命令行模式 parted option device command 该
  • 【原创】第一个iOS应用程序

    摘要 第一个iOS应用程序 包括获取控件 绑定事件 设置属性等内容 iOS Objective C 目录 第一章 窗口与应用程序 第二章 添加视图 2 1 从nib文件初始化视图 2 2 使用脚本添加视图 第三章 添加子视图 3 1 通过x
  • 制作自己的 Kindle 电子书

    想象以下场景 你刚收到一台新的 Kindle Paperwhite 心中已然响起了轰轰烈烈的 我今年 或这个冬天 一定要阅读 100 本书 结果发现 想看的书 Amazon 上找不到 或者排版很糟糕 如何解决 自己动手做呗 准备工作 我使用
  • UE4 UI实现改键功能

    主要内容 本文主要讲解如何在UI中实现自定义按键的功能类似于游戏中的改键操作 用到的是UE4自带的第三人称案例 因为第三人称自带了小白人和几个按键绑定就不用再手动去设置 实现步骤 1 创建两个UMG用来展示UI效果 1 创建WBP Key
  • C++链表合并

    有l1和l2两个链表 这两个链表降序排列 把l2合并到l1中 并按降序排列 同时清空l2链表 例如l1 9 8 7 6 l2 12 11 10 5 4 3 2 1 合并后l1 12 11 10 9 8 7 6 5 4 3 2 1 l2 in
  • 【Android】利用intent启动浏览器

    文章目录 一 默认浏览器 二 指定浏览器 三 选择浏览器 一 默认浏览器 需要设置Action和Date属性 构造 Uri uri Uri parse https www baidu com Intent intent new Intent
  • SCADE Suite 状态机之变量隐式赋值

    SCADE Suite 状态机之变量隐式赋值 1 变量的隐式赋值 目的 简化模型设计 Last 只要没有显示赋值 便取上一周期的数值 Default 只要没有显示赋值 便取默认设置的数值 优先级更高 设置方法 2 定义变量的Last值 1
  • LeetCode 817:链表组件(计数)

    解法一 常规解法 建图 DFS 时间复杂度O n O n 空间复杂度因为需要存储图 所以是O n 这种方法是通解 对于所有图都适用 Definition for singly linked list struct ListNode int
  • lua元表以及元方法

    知微出凡 lua元表以及元方法 lua中的变量是没有数据类型的 值有类型 类型有八种nil number boolean string function thread userdata以及table Lua 中的每个值都可以有一个 元表 这