具有动态名称的全局变量

简介: 具有动态名称的全局变量

通常,赋值操作对于访问和设置全局变量已经足够了。然而,有时我们也需要某些形式的元编程meta-programming )。例如,我们需要操作一个全局变量,而这个全局变量的名称却存储在另一个变量中或者经由运行时计算得到。为了获取这个变量的值,许多程序员会写出如下的代码:

value = load("return" .. varname)()


例如,如果 varnamex ,那么字符串连接的结果就是 "return x" ,当执行时就能得到期望的结果。然而,在这段代码代码中涉及一个新代码段的创建和编译,在一定程度上开销昂贵。我们可以使用下面的代码来实现相同的效果,但效率却比之前的高出一个数量级:

value = _G[varname]


由于全局环境是一个普通的表,因此可以简单地使用对应的(变量名)直接进行索引。


类似地,我们可以通过编写 _G[varname] = value 给一个名称为动态计算出的全局变量赋值。不过,请注意,有些程序员对于这种机制的使用可能有些过度而写出诸如 _G["a"]=_G["b"] 这样的代码,而这仅仅是 a=b 的一种复杂写法。


上述问题的一般化形式是,允许字段使用诸如 "io.read""a.b.c.d" 这样的动态名称。如果直接使用 _G["io.read"] ,显然是不能从表 io 中得到字段 read 的。但我们可以编写一个函数 getfieldgetfield("io.read") 返回想要的结果。这个函数主要是一个循环,从 _G 开始逐个字段地进行求值:

function getfield(f)
  local v = _G        -- 从全局表开始
  for w in string.gmatch(f, "[%a_][%w_]*") do
    v = v[w]
  end
  return v
end


我们使用函数 gmatch 来遍历f中的所有标识符。


与之对应的设置字段的函数稍显复杂。像 a.b.c.d = v 这样的赋值等价于以下的代码:

local temp = a.b.c
temp.d = v


也就是说,我们必须一直取到最后一个名称,然后再单独处理最后的这个名称。下述代码的函数 setfield 完成了这个需求,并且同时创建了路径中不存在路径对应的中间表:

function setfield (f, v)
  local t = _G                                              -- 从全局表开始
  for w, d in string.gmatch(f, "([%a_][%w_]*)(%.?)") do
    if d == "." then                                        -- 不是最后一个名字?
      t[w] = t[w] or {}                                     -- 如果不存在则创建表
      t = t[w]                                              -- 获取表
    else                                                    -- 最后一个名字
      t[w] = v                                              -- 进行赋值
    end
  end
end


上述代码中使用的模式将捕获字段名称保存在变量 w 中,并将其后可选的点保存在变量 d 中。如果字段名后没有点,那么该字段就是最后一个名称。


下面的代码通过上面代码中的函数创建了全局表 tt.x ,并将 10 赋给了 t.x.y

setfield("t.x.y", 10)
print(t.x.y)                --> 10
print(getfield("t.x.y"))    --> 10
目录
相关文章
|
6月前
|
C++
VS项目属性变量
VS项目属性变量
|
6月前
|
编译器 C# 开发者
C# 10.0中的全局`using`指令:简化命名空间引用的新方式
【1月更文挑战第4天】本文介绍了C# 10.0中引入的全局`using`指令,该指令允许开发者在项目级别统一管理命名空间引用,从而消除源文件中重复的`using`语句。全局`using`指令通过减少冗余代码、提高可维护性和统一命名空间管理,为开发者带来了更高效的编码体验。文章详细解释了如何实现全局`using`指令,并探讨了其在实际项目中的优势和适用场景。
|
18天前
|
存储 安全 编译器
【c++】深入理解别名机制--引用
本文介绍了C++中的引用概念及其定义、特性、实用性和与指针的区别。引用是C++中的一种别名机制,通过引用可以实现类似于指针的功能,但更安全、简洁。文章详细解释了引用的定义方式、引用传参和返回值的应用场景,以及常引用的使用方法。最后,对比了引用和指针的异同,强调了引用在编程中的重要性和优势。
32 1
|
6月前
|
存储 C# 容器
掌握 C# 变量:在代码中声明、初始化和使用不同类型的综合指南
变量是用于存储数据值的容器。 在 C# 中,有不同类型的变量(用不同的关键字定义),例如: int - 存储整数(没有小数点的整数),如 123 或 -123 double - 存储浮点数,有小数点,如 19.99 或 -19.99 char - 存储单个字符,如 'a' 或 'B'。Char 值用单引号括起来 string - 存储文本,如 "Hello World"。String 值用双引号括起来 bool - 存储具有两个状态的值:true 或 false
103 2
|
6月前
|
Shell
变量的定义和引用
变量的定义和引用。
80 0
|
缓存 运维 监控
【运维知识进阶篇】Ansible变量详解(变量定义+变量优先级+变量注册+层级定义变量+facts缓存变量)
【运维知识进阶篇】Ansible变量详解(变量定义+变量优先级+变量注册+层级定义变量+facts缓存变量)
379 0
|
数据安全/隐私保护
设置公共变量
主题:公共变量的设置
西门子S7-1200PLC变量表如何使用?如何声明、选用、显示、定义、更改变量?变量保持性如何设置?
在S7-1200 CPU的编程理念中,特别强调符号寻址的使用,在开始编写程序之前,用户应当为输入、输出、中间变量定义相应的符号名,也就是标签。具体步骤如下:
西门子S7-1200PLC变量表如何使用?如何声明、选用、显示、定义、更改变量?变量保持性如何设置?
|
小程序
为小程序自定义全局方法和全局变量
原生小程序项目开发中,有这个情景,需要将某个方法或者变量,定义到全局变量,来方便全局使用
414 0
使用静态公共变量传参
第一步 在自己要傳參的頁面定義
81 0