15、Lua 元表(Metatable)

Lua 元表

  • Lua 元表(Metatable)
  • __index 元方法
  • __newindex 元方法
  • 为表添加操作符
  • __call 元方法
  • __tostring 元方法

Lua 元表(Metatable)

在Lua table 中我们可以访问对应的key来得到value值,但是却无法对两个 table 进行操作。
因此Lua 提供了元表(Metatable),允许我们改变table的行为,每个行为关联了对应的元方法。
例如,使用元表我们可以定义Lua如何计算两个table的相加操作a+b。

当Lua试图对两个表进行相加时,先检查两者之一是否有元表,之后检查是否有一个叫 __add 的字段,若找到,则调用对应的值。__add 等即时字段,其对应的值(往往是一个函数或是table)就是 元方法

有两个很重要的函数来处理元表:

  • setmetatable(table,metatable): 对指定table设置元表(metatable),如果元表(metatable)中存在__metatable键值,setmetatable会失败 。
  • getmetatable(table): 返回对象的元表(metatable)。

以下实例演示了如何对指定的表设置元表:

mytable = {}                          -- 普通表 
mymetatable = {}                      -- 元表
setmetatable(mytable,mymetatable)     -- 把 mymetatable 设为 mytable 的元表 

以上代码也可以直接写成一行:

mytable = setmetatable({},{})

以下为返回对象元表:

getmetatable(mytable)                 -- 这回返回mymetatable

__index 元方法

这是metatable 最常用的键。
当你通过键来访问 table 的时候,如果这个键没有值,那么Lua就会寻找该table的metatable(假定有metatable)中的__index 键。如果__index包含一个表格,Lua会在表格中查找相应的键。

我们可以在使用 lua 命令进入交互模式查看:

$ lua
Lua 5.3.0  Copyright (C) 1994-2015 Lua.org, PUC-Rio
> other = { foo = 3 } 
> t = setmetatable({}, { __index = other }) 
> t.foo
3
> t.bar
nil

如果__index包含一个函数的话,Lua就会调用那个函数,table和键会作为参数传递给函数。

__index 元方法查看表中元素是否存在,如果不存在,返回结果为 nil;如果存在则由 __index 返回结果。

mytable = setmetatable({key1 = "value1"}, {__index = function(mytable, key)if key == "key2" thenreturn "metatablevalue"elsereturn nilendend
})print(mytable.key1,mytable.key2)

实例输出结果为:

value1  metatablevalue

实例解析:

  • mytable 表赋值为 {key1 = “value1″}
  • mytable 设置了元表,元方法为 __index。
  • 在mytable表中查找 key1,如果找到,返回该元素,找不到则继续。
  • 在mytable表中查找 key2,如果找到,返回该元素,找不到则继续。
  • 判断元表有没有__index方法,如果__index方法是一个函数,则调用该函数。
  • 元方法中查看是否传入 “key2” 键的参数(mytable.key2已设置),如果传入 “key2” 参数返回 “metatablevalue”,否则返回 mytable 对应的键值。

我们可以将以上代码简单写成:

mytable = setmetatable({key1 = "value1"}, { __index = { key2 = "metatablevalue" } })
print(mytable.key1,mytable.key2)

__newindex 元方法

__newindex 元方法用来对表更新,__index则用来对表访问 。

当你给表的一个缺少的索引赋值,解释器就会查找__newindex 元方法:如果存在则调用这个函数而不进行赋值操作。

以下实例演示了 __newindex 元方法的应用:

mymetatable = {}
mytable = setmetatable({key1 = "value1"}, { __newindex = mymetatable })print(mytable.key1)mytable.newkey = "新值2"
print(mytable.newkey,mymetatable.newkey)mytable.key1 = "新值1"
print(mytable.key1,mymetatable.newkey1)

以上实例执行输出结果为:

value1
nil    新值2
新值1    nil

以上实例中表设置了元方法 __newindex,在对新索引键(newkey)赋值时(mytable.newkey = “新值2″),会调用元方法,而不进行赋值。而如果对已存在的索引键(key1),则会进行赋值,而不调用元方法 __newindex。

以下实例使用了 rawset 函数来更新表:

mytable = setmetatable({key1 = "value1"}, {__newindex = function(mytable, key, value)rawset(mytable, key, "\""..value.."\"")end
})mytable.key1 = "new value"
mytable.key2 = 4print(mytable.key1,mytable.key2)

以上实例执行输出结果为:

new value  "4"

为表添加操作符

以下实例演示了两表相加操作:

-- 计算表中最大值,table.maxn在Lua5.2以上版本中已无法使用
-- 自定义计算表中最大值函数 table_maxn
function table_maxn(t)local mn = 0for k, v in pairs(t) doif mn < k thenmn = kendendreturn mn
end-- 两表相加操作
mytable = setmetatable({ 1, 2, 3 }, {__add = function(mytable, newtable)for i = 1, table_maxn(newtable) dotable.insert(mytable, table_maxn(mytable)+1,newtable[i])endreturn mytableend
})secondtable = {4,5,6}mytable = mytable + secondtablefor k,v in ipairs(mytable) do
print(k,v)
end

以上实例执行输出结果为:

1   1
2   2
3   3
4   4
5   5
6   6

__add 键包含在元表中,并进行相加操作。 表中对应的操作列表如下:

模式描述
_add对应的运算符 +
__sub对应的运算符 -
__mul对应的运算符 *
__div对应的运算符 /
__mod对应的运算符 %
__unm对应的运算符 -
__concat对应的运算符 ..
__eq对应的运算符 ==
__lt对应的运算符 <
__le对应的运算符 <=

__call 元方法

__call 元方法在 Lua 调用一个值时调用。以下实例演示了计算表中元素的和:

-- 计算表中最大值,table.maxn在Lua5.2以上版本中已无法使用
-- 自定义计算表中最大值函数 table_maxn
function table_maxn(t)local mn = 0for k, v in pairs(t) doif mn < k thenmn = kendendreturn mn
end-- 定义元方法__call
mytable = setmetatable({10}, {__call = function(mytable, newtable)sum = 0for i = 1, table_maxn(mytable) dosum = sum + mytable[i]endfor i = 1, table_maxn(newtable) dosum = sum + newtable[i]endreturn sumend
})
newtable = {10,20,30}
print(mytable(newtable))

以上实例执行输出结果为:

70

__tostring 元方法

__tostring 元方法用于修改表的输出行为。以下实例我们自定义了表的输出内容:

mytable = setmetatable({ 10, 20, 30 }, {__tostring = function(mytable)sum = 0for k, v in pairs(mytable) dosum = sum + vendreturn "表所有元素的和为 " .. sumend
})
print(mytable)

以上实例执行输出结果为:

表所有元素的和为 60

从本文中我们可以知道元表可以很好的简化我们的代码功能,所以了解 Lua 的元表,可以让我们写出更加简单优秀的 Lua 代码。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/793352.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

《QT实用小工具·十二》邮件批量发送工具

1、概述 源码放在文章末尾 该项目实现了邮件的批量发送&#xff0c;如下图所示&#xff1a; 项目部分代码如下所示&#xff1a; #ifndef SMTPCLIENT_H #define SMTPCLIENT_H#include <QtGui> #include <QtNetwork> #if (QT_VERSION > QT_VERSION_CHECK(5,0,…

初识CSS

目录 前言&#xff1a; CSS的介绍&#xff1a; CSS的发展&#xff1a; 1&#xff09;CSS1.0&#xff1a; 2)CSS2.0: 3)CSS2.1: 4&#xff09;CSS3&#xff1a; CSS特点&#xff1a; 1&#xff09;丰富的样式定义&#xff1a; 2&#xff09;易于设置和修改&#xff1a; 3&…

彩虹聚合DNS管理系统,附带系统搭建教程

聚合DNS管理系统&#xff0c;可以实现在一个网站内管理多个平台的域名解析&#xff0c;目前已支持的域名平台有&#xff1a;阿里云、腾讯云、华为云、西部数码、CloudFlare。 本系统支持多用户&#xff0c;每个用户可分配不同的域名解析权限&#xff1b;支持API接口&#xff0…

Flask Response生成流式数据api;iter_lines,iter_content流式数据遍历区别

1、Flask Response生成流式数据api 注意return与def generate():是同级的 from flask import Flask, Responseapp Flask(__name__)app.route(/stream) def stream_data():def generate():for i in range(5):time.sleep(1)yield f"Data chunk {i}\0" # 在每个数据…

卷积神经网络-池化层

卷积神经网络-池化层 池化层&#xff08;Pooling Layer&#xff09;是深度学习神经网络中的一个重要组成部分&#xff0c;通常用于减少特征图的空间尺寸&#xff0c;从而降低模型复杂度和计算量&#xff0c;同时还能增强模型的不变性和鲁棒性。 池化操作通常在卷积神经网络&am…

doesn‘t contain a valid partition table

查看硬盘空间 $ fdisk -l Disk /dev/mmcblk0: 29 GB, 31037849600 bytes, 60620800 sectors 947200 cylinders, 4 heads, 16 sectors/track Units: sectors of 1 * 512 512 bytesDisk /dev/mmcblk0 doesnt contain a valid partition table Disk /dev/mmcblk0p1: 1 MB, 10485…

动态规划:线性dp

1.最长公共子序列(LCS) dp[i][j]含义&#xff1a;序列Ai(a1-ai)和Bj(b1-bj)的最长公共子序列长度 分析两种情况&#xff1a; &#xff08;1&#xff09;当ai bj时&#xff0c;已经求得Ai-1和Bj-1的最长公共子序列 dp[i][j] dp[i-1][j-1] 1 &#xff08;2&#xff09;当…

2024 年最新使用 Wechaty 开源框架搭建部署微信机器人(微信群智能客服案例)

读取联系人信息 获取当前机器人账号全部联系人信息 bot.on(ready, async () > {console.log("机器人准备完毕&#xff01;&#xff01;&#xff01;")let contactList await bot.Contact.findAll()for (let index 0; index < contactList.length; index) {…

第三方短信-短信合作-106短信

第三方短信-短信合作-106短信 1、你是否也有需要发送短信的业务、但是自己没有短信服务的情况 2、是否需要大量发送短信、但是又不想通过自己的真实手机号发 3、您是否是开发者、但是没有自己的短信服务&#xff0c;需要发送短信可以使用/借用我的短信服务进行发送&#xff0c…

电梯轿厢内电动车数据集,VOC标签格式已标注(数据集+训练好的权重)

本数据集用于电梯禁入电动车项目的目标检测算法模型训练任务。 共有4000张左右图片&#xff0c;全部为电梯监控真实照片&#xff0c;没有网络爬虫滥竽充数的图片&#xff0c;并已经分好数据集和验证集&#xff0c;可直接用来训练。以上图片均一一手工标注&#xff0c;标签格式为…

YoloV8改进策略:BackBone改进|ELA

文章目录 摘要1、引言2、相关工作3、方法3.1、重新审视坐标注意力3.1.1、坐标注意力3.1.2、坐标注意力的不足 3.2、高效局部注意力3.3、多个ELA版本设置3.4、可视化3.5、实现 4、实验4.1、实验细节4.2、ImageNet上的图像分类4.3、目标检测4.4、语义分割 5、结论 摘要 https://…

zdpreact_antdesginpro 研究一下react里面比较流行的一个UI框架,开发后台管理系统

首先看一下最开始的代码&#xff1a; 这里面大部分的东西都可以删掉&#xff0c;比如README&#xff0c;只留下中文的那个就可以了。 之后看看README.md中介绍的特性。 特性 &#x1f4a1; TypeScript: 应用程序级 JavaScript 的语言&#x1f4dc; 区块: 通过区块模板快速…

【设计模式】-单例模式

简介 单例模式是一种创建型设计模式&#xff0c;确保某个类仅有一个实例&#xff0c;并提供一个全局访问点来访问该实例。 在单例模式中&#xff0c;类负责创建自己的对象&#xff0c;同时确保只有单个对象被创建。这个类提供了一种访问其唯一对象的方式&#xff0c;允许直接访…

【Linux】网络基础常识{OSI七层模型/ TCP/IP / 端口号 /各种协议}

文章目录 1.网络常识1.0DHCP协议1. 1IP地址/MAC地址/ARP协议是什么&#xff1f;IP/MACARP&#xff1a;IP ⇒ MAC 1.2手机连接wifi的原理 SSID与BSSID手机连接wifiSSID与BSSID 1.3手机如何通过“数据/流量”上网&#xff1f;1.4电脑连接wifi的原理&#xff1f;电脑通过热点上网…

C++ 11 的新特性

回答来自【通义灵码】 C11是C编程语言的一个重要里程碑&#xff0c;引入了大量的新特性以提升代码的可读性、可维护性、性能和安全性。以下是一些关键的C11新特性&#xff1a; 统一初始化: 允许在任何情况下使用花括号列表初始化&#xff08;uniform initialization&#xff0…

RH850P1X芯片学习笔记-Clocked Serial Interface H (CSIH)

文章目录 Features of RH850/P1x-C CSIHUnitsRegister Base AddressClock SupplyInterrupt RequestsHardware ResetExternal Input/Output Signals数据一致性检查 OverviewFunctional OverviewFunctional Overview DescriptionBlock Diagram RegistersList of RegistersCSIHnCT…

python怎么存储数据

在Python开发中&#xff0c;数据存储、读取是必不可少的环节&#xff0c;而且可以采用的存储方式也很多&#xff0c;常用的方法有json文件、csv文件、MySQL数据库、Redis数据库以及Mongdb数据库等。 1. json文件存储数据 json是一种轻量级的数据交换格式&#xff0c;采用完全…

【教学类-09-09】20240406细线迷宫图05(正方形)30格+动物+箭头(15CM横版一页-1份横版)

作品展示&#xff1a; 背景需求&#xff1a; 增加迷宫图的吸引力&#xff0c;起点的地方放一个小动物。 素材准备&#xff1a; 图片来自midjounery文生图&#xff08;四图&#xff09;&#xff0c;但同种动物只留1个&#xff08;如4个老鼠只保留一只老鼠&#xff09;&#xff…

哈希表2s总结

3.哈希表 哈希表非常常用&#xff0c;字典一般会用来保存处理过后的输入输出信息&#xff0c;集合也可以用来去重&#xff0c;这部分是重点&#xff0c;但是还是那句话&#xff0c;这种题目是不会或者说很少考原题的&#xff0c;主要还是学习知识&#xff0c;所以题目看一下答…

如何保证Redis的缓存和数据库中的数据的一致性?

Redis的缓存如何和数据库中的数据保持一致性&#xff1f; 我们都知道&#xff0c;Redis是一个基于内存的键值存储系统&#xff0c;数据完全存放在内存中&#xff0c;这使得它的读写速度远超传统的硬盘存储数据库。对于高访问频率、低修改率的数据&#xff0c;通过将它们缓存在…