具有动态名称的全局变量

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

通常,赋值操作对于访问和设置全局变量已经足够了。然而,有时我们也需要某些形式的元编程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
目录
相关文章
|
5月前
|
C++
VS项目属性变量
VS项目属性变量
|
5月前
|
程序员 C语言
用户自定义结构体类型
用户自定义结构体类型
44 0
|
5月前
|
存储 C# 容器
掌握 C# 变量:在代码中声明、初始化和使用不同类型的综合指南
变量是用于存储数据值的容器。 在 C# 中,有不同类型的变量(用不同的关键字定义),例如: int - 存储整数(没有小数点的整数),如 123 或 -123 double - 存储浮点数,有小数点,如 19.99 或 -19.99 char - 存储单个字符,如 'a' 或 'B'。Char 值用单引号括起来 string - 存储文本,如 "Hello World"。String 值用双引号括起来 bool - 存储具有两个状态的值:true 或 false
83 2
|
缓存 运维 监控
【运维知识进阶篇】Ansible变量详解(变量定义+变量优先级+变量注册+层级定义变量+facts缓存变量)
【运维知识进阶篇】Ansible变量详解(变量定义+变量优先级+变量注册+层级定义变量+facts缓存变量)
303 0
|
数据安全/隐私保护
设置公共变量
主题:公共变量的设置
|
存储 缓存 编译器
C/C++函数与变量前面的标识符的作用
C/C++函数与变量前面的标识符的作用
180 4
C/C++函数与变量前面的标识符的作用
|
小程序
为小程序自定义全局方法和全局变量
原生小程序项目开发中,有这个情景,需要将某个方法或者变量,定义到全局变量,来方便全局使用
393 0
使用静态公共变量传参
第一步 在自己要傳參的頁面定義
74 0
|
JavaScript 开发者
路由-关于命名视图的名称到底是变量还是字符串的说明|学习笔记
快速学习路由-关于命名视图的名称到底是变量还是字符串的说明
|
Python
PyQt5 技巧篇-增加一个类级变量,类级变量的设置方法,类级“常量“设置方法
PyQt5 技巧篇-增加一个类级变量,类级变量的设置方法,类级“常量“设置方法
322 0