当前位置: 首页 > news >正文

Lua 中的 __index、__newindex、rawget 与 rawset 介绍

原文地址:Lua 中的 __index、__newindex、rawget 与 rawset 介绍

欢迎参观我的网站:无敌牛 – 技术/著作/典籍/分享等

在 Lua 中,表(table)是最核心的数据结构。通过为其设置“元表”(metatable),我们可以改变表在某些操作下的默认行为。其中,__index__newindex 是两个最常用的元方法,而 rawgetrawset 是与之配套的“绕过元表”的操作函数。理解它们的作用和关系,有助于更灵活、安全地使用 Lua 表。


一、__index —— 读取不存在的键时的行为

当访问一个表中不存在的键时(例如 t.keyt["key"]),如果该表设置了元表,且元表中包含 __index 字段,Lua 就会调用它。

__index 可以是一个函数,也可以是一个

示例 1:__index 是函数

local t = {}
local mt = {__index = function(tbl, key)print("访问了不存在的键:", key)return nilend
}
setmetatable(t, mt)print(t.name)  -- 输出: 访问了不存在的键: name-- 然后输出: nil

示例 2:__index 是表(常用于“默认值”或“继承”)

local defaults = { x = 0, y = 0 }
local obj = {}
setmetatable(obj, { __index = defaults })print(obj.x)  -- 0(从 defaults 获取)
print(obj.z)  -- nil(defaults 里也没有)

注意:如果键在表中已存在,则不会触发 __index


二、__newindex —— 写入不存在的键时的行为

当给一个表中原本不存在的键赋值时(例如 t.key = value),如果该表有元表且定义了 __newindex,Lua 会调用它,而不是直接赋值。

__index 一样,__newindex 也可以是函数或表。

示例 1:__newindex 是函数(常用于拦截、校验、日志)

local t = {}
local mt = {__newindex = function(tbl, key, value)print("尝试设置:", key, "=", value)-- 可选择是否真正写入rawset(tbl, key, value)  -- 使用 rawset 避免递归end
}
setmetatable(t, mt)t.name = "Alice"  -- 输出: 尝试设置: name = Alice
print(t.name)     -- Alice

示例 2:__newindex 是表(常用于“写入重定向”)

local storage = {}
local proxy = {}
setmetatable(proxy, { __newindex = storage })proxy.x = 10
proxy.y = 20print(proxy.x, proxy.y)     -- nil, nil(proxy 本身没写入)
print(storage.x, storage.y) -- 10, 20(写入到了 storage)

注意:

  • 如果键已存在,赋值不会触发 __newindex
  • __newindex 函数内直接写 tbl[key] = value 会导致无限递归,应使用 rawset

三、rawgetrawset —— 绕过元表的直接操作

有时我们希望跳过元表机制,直接对表进行读写。这时就需要 rawgetrawset

  • rawget(t, key) → 直接获取 t[key],不触发 __index
  • rawset(t, key, value) → 直接设置 t[key] = value,不触发 __newindex

示例:

local t = { x = 1 }
local mt = {__index = function() return "from __index" end,__newindex = function() error("禁止写入") end
}
setmetatable(t, mt)print(t.y)           -- "from __index"
print(rawget(t, "y")) -- nil(直接读,不触发 __index)-- t.z = 99         -- 会报错:禁止写入
rawset(t, "z", 99)   -- ✅ 成功,绕过 __newindex
print(t.z)           -- 99

这两个函数在元方法内部操作表时尤其重要,可以避免触发元表导致的递归或副作用。


四、常见使用场景小结

场景推荐方案
提供默认值或实现继承__index = 表
拦截读取做日志或计算__index = 函数
实现只读表__newindex = 报错函数
数据校验或属性封装__newindex = 校验函数 + rawset
避免元表干扰或递归使用 rawget / rawset
在元方法内部安全读写表必须使用 rawget / rawset

五、注意事项

  1. __index__newindex 只对“不存在的键”生效
  2. __index__newindex 函数中操作表时,务必使用 rawget / rawset,否则可能触发递归。
  3. 元方法不会被继承 —— 子表必须显式设置自己的元表。
  4. 性能敏感的代码中,频繁触发元方法会有开销,可考虑用 rawget / rawset 优化。

总结

__index__newindexrawgetrawset 是 Lua 元表机制中最基础也最实用的组成部分。它们不复杂,但在构建配置系统、对象模型、数据代理、调试工具时非常有用。

http://www.dtcms.com/a/490311.html

相关文章:

  • CAN、ROS数据录制与rqt图形化显示
  • 基于深度学习的卫星图像分类(Kaggle比赛实战)
  • 银河麒麟 aarch64 linux 里面的 qt 发布应用怎么打包
  • linux常用命令(6)——网络管理
  • 江阴建设局网站招考设计说明500字通用
  • Lab Deploying Multi-container Applications
  • 目标检测2
  • 12-用户管理
  • 合肥哪里做网站西安网站建设制作专业公司
  • 中冶东北建设网站装修网站运营
  • Nginx+Lua动态加载黑名单
  • 吕口*了多乐*-(话题)程序系统架构方案
  • Java Spring 框架的`@Autowired` 注解 以及依赖注入分析
  • [Docker集群] Docker 数据持久化
  • MCP vs. API:AI智能体如何更轻松地连接外部世界?
  • 【XR硬件系列】破局“芯”瓶颈:深入浅出解析XR专用芯片的必然性
  • 浙江省建设培训中心的网站小程序开发公司简介
  • Redis 限流解决方案:结合 Lua 脚本、AOP 和自定义注解的实现
  • 游戏画面卡顿残影?这款电竞显示器610Hz + 4K OLED
  • COLMAP原理讲解与使用教程
  • 定位守护童年,科技构筑安全屏障
  • AWS EC2 Jenkins 自动化部署与 Python 环境管理
  • Linux中快速部署Elasticsearch(基础TLS配置)
  • 2025吉比特-游戏引擎开发-一面复盘
  • java数据结构--List的介绍
  • 网站主页不收录肥城房产网
  • 计算机视觉(opencv)——基于 MediaPipe 的实时面部表情识别
  • C++设计模式_行为型模式_观察者模式Observer(发布-订阅(Publish-Subscribe))
  • 怎么解决ModuleNotFoundError: No module named ‘Cython‘
  • 电子商务网站规划流程手机主题制作网站