Lua 只读表

ops/2024/10/18 12:25:27/

Lua 的 table 建立只读机制,保护 table 不能被随意修改。

建立只读机制

Lua 的 table 通常情况下是可以随意修改字段的值,或者新增字段。

如果想要建立只读机制,保护表只能读取,而不能被随意修改,可以利用元表。

禁止新增字段

首先,利用 __newindex,可以禁止新增字段。

例如,现在有一个 student 表,包含 name 和 age。

定义一个 mt 表,__newindex 打印只读提示。

给 student 表设置元表 mt。

lua">local student = {name = "Alice",age = 18
}local mt = {__newindex = function ()print("Can not modify a readonly table")end
}setmetatable(student, mt)

现在可以读取字段,但是不能新增字段了。

例如给 student 增加一个 score 字段,但是会打印只读提示,没有赋值,尝试打印 score 字段会输出 nil。

lua">local name = student.name
print(name)  -- Alicestudent.score = 0     -- Can not modify a readonly table
print(student.score)  -- nil

禁止修改字段

经过上述步骤后,虽然不能新增字段,但还是可以对已有的字段进行修改。

lua">student.age = 20
print(student.age)  -- 20

Lua 没有提供修改字段的元方法,不过我们可以利用空表,把修改字段的行为,转化成新增字段的行为。

因为对于空表来说,访问任何字段都是不存在的,都会是新增字段的行为。

修改一下之前的代码,定义一个 empty 表,给 empty 设置元表 mt,元表里定义 __index,赋值为 student。

lua">local student = {name = "Alice",age = 18
}local empty = {}
local mt = {__index = student,__newindex = function ()print("Can not modify a readonly table")end
}
setmetatable(empty, mt)

此时,访问 empty 表,是不能修改字段值的。

lua">empty.age = 20    -- Can not modify a readonly table
print(empty.age)  -- 18

不过,此处仍然可以直接去修改 student 表,所以需要对这套方法做一个封装。

封装只读函数

定义一个全局函数 Readonly,把上述的步骤放到函数中,接收一个 table,返回经过处理的空表。

lua">Readonly = function (table)local empty = {}local mt = {__index = table,__newindex = function ()print("Can not modify a readonly table")end}setmetatable(empty, mt)return empty
endlocal student = {name = "Alice",age = 18
}
student = Readonly(student)

再尝试一下修改 student,已经不能修改字段的值了。

lua">student.age = 20    -- Can not modify a readonly table
print(student.age)  -- 18

嵌套表

上面的只读函数只能处理一层表,如果表里面还嵌套了表,那么嵌套的表还是非只读的。

此时可以递归检查表里是否有嵌套表。

lua">Readonly = function (table)-- 遍历每个字段for key, value in pairs(table) do-- 有嵌套表if type(value) == "table" then-- 递归设置只读table[key] = Readonly(value)endend-- 设置只读的步骤local empty = {}local mt = {__index = table,__newindex = function ()print("Can not modify a readonly table")end}setmetatable(empty, mt)return empty
end

在 student 表里新增一个 score 表,包含 math 和 english 字段。

经过只读函数递归处理之后,score 表也是只读的。

lua">local student = {name = "Alice",age = 18,score = {math = 100,english = 100}
}
student = Readonly(student)student.score.math = 20    -- Can not modify a readonly table
print(student.score.math)  -- 100

http://www.ppmy.cn/ops/52293.html

相关文章

网络安全和信息安全

概述 信息安全、网络安全与网络空间安全是当前信息技术领域内的三个重要概念,它们在某些方面有着紧密的联系,同时在不同的语境和应用场景下又有所区别。本次分析旨在深入理解这三个概念的定义、内涵及其相互关系,以便更好地应用于实际工作中…

VSCode美化

VSCode 美化 主题推荐 Catppuccin Noctis 这款主题融合了 Catppuccin 主题的配色和 Noctis 主题的高亮方案,作为 Catppuccin 主题的替代品。 Tokyo Night Tokyo Night 主题颜色偏黑,其变体 Tokyo Night Storm 则略微发蓝,配合峡谷背景效…

mysql索引以及优化

索引的作用 在数据库表中对字段建立索引可以大大提高查询速度 mysql索引类型 普通索引唯一索引: 唯一索引列的值必须唯一允许有空值,如果是组合索引,则列值的组合必须唯一create unique index indexName on mytable(username(length))修改表结…

36.Http协议的设计与解析

Http协议比Redis协议复杂的多,如果程序员自己去实现,工作量大。 Netty已经把Http协议的编解码器实现好了,只需要简单的配置就可以使用。 做一个http的服务端需要HttpServerCodec。 看它继承的父类: 结合了两个类: HttpRequestDecoder(入站处理器extends Channelnbound…

温控系统-DAL数据层(2)BaseDAL和ProductDAL功能代码

BaseDAL是数据层中非常重要的基类,业务DAL使用到其中一些共用方法; ProductDAL.cs结构如下参考: using Common; using STMS.DbUtility; using STMS.Models.DModels; using System; using System.Collections.Generic; using System.Data.Sq…

vue 利用element的Table 表格实现自制的穿梭框(可以高度自定义)_vue 穿梭框

2. 其实可以从最后的效果图看出这个自制的穿梭框,只是由两个table表格和两个按钮组成,只需要写其中逻辑事件即可完成穿梭框的效果,其中的事件主要分为“选中”,“穿梭”和“删除”,其实也只是关于数组的增,…

汇编快速入门

一.基础知识 1.数据类型 DB(Define Byte,字节类型 占位8位bit 1字节) 范围:DB可以用来定义(无符号、有符号)整数(包含二、十、十六进制)和字符 语法:a DB 数据个数…

关于小程序内嵌H5页面交互的问题?

有木有遇到?有木有遇到。 小程序内嵌了H5,然后H5某个按钮,需要打开小程序某个页面进行信息完善或登记,登记后要返回H5页面,而H5页面要动态显示刚才在小程序页面登记的信息。 操作流程是这样: 方案1&#…