访问非局部变量

简介: 访问非局部变量

调试库开提供了函数 getupvalue ,该函数允许我们访问一个被 Lua 函数所使用的非局部变量。与局部变量不同,被一个函数所引用的非局部变量即使在引用它的函数已经不活跃的情况下也会一致存在(毕竟这就是闭包的实质)。因此,函数 getupvalue 的第一个参数不是栈层次,而是一个函数(更确切的说,是一个闭包)。函数 getupvalue 的第二个参数是变量索引Lua 语言按照函数引用非局部变量的顺序对他们编号;但由于一个函数不能用同一名称访问两个非局部变量,所以这个顺序是无关紧要的。


我们还可以通过函数 debug.setupvalue 更新非局部变量的值。该函数有三个参数:一个闭包、一个变量索引和一个新值。与函数 setlocal 一样,该函数返回变量名,如果变量索引超出范围则返回 nil


下述示例演示了如何通过变量名访问一个函数中变量的值:

function getvarvalue(name, level, isenv)
  local value
  local found = false
  level = (level or 1) + 1
  -- 尝试局部变量
  for i = 1, math.huge do
    local n, v = debug.getlocal(level, i)
    if not n then break end
    if n == name then
      value = v
      found = true
    end
  end
  if found then return "local", value end
  -- 尝试非局部变量
  local func = debug.getinfo(level, "f").func
  for i =1, math.huge do
    local n, v = debug.getupvalue(func, i)
    if not n then break end
    if n == name then return "upvalue", v end
  end
  if isenv then return "noenv" end        -- 避免循环
  -- 没找到;从环境中获取值
  local _, env = getvarvalue("_ENV", level, true)
  if env then
    return "global", env[name]
  else
    return "noenv"
  end
end


用法如下:

> local a = 4; print(getvarvalue("a"))      --> local   4
> a = "xx"; print(getvarvalue("a"))         --> global  xx


参数 level 指明在那个栈层次中寻找函数, 1 (默认值)意味着直接的调用者。代码中多加的 1 将层次纠正为包括 getvarvalue 自己。


该函数首先查找局部变量。如果有多个局部变量的名称与给定的名称相同,则获取具有最大索引的那个局部变量。因此,函数必须执行完整的循环。如果找不到指定名称的局部变量,那么就查找非局部变量。为了遍历非局部变量,该函数使用 debug.getinfo 函数获取调用闭包,然后遍历非局部变量。最后,如果还是找不到指定名字的非局部变量,就检索全局变量:该函数递归的调用自己来访问合适的 _ENV 变量并在相应环境中查找指定的名字。


参数 isenv 避免了一个诡异的问题。该参数用于说明我们是否处于一个从 _ENV 变量中查询全局名称的递归调用中。一个不使用全局变量的函数可能没有上值 _ENV 。在这种情况下,如果我们试图把 _ENV 当做全局变量来查询,那么由于我们需要 _ENV 来得到其自身的值,所以可能会陷入无限递归循环。因此,当 isenv 为真且函数 getvarvalue 找不到局部变量或上值时, getvarvalue 就不应该再尝试全局变量。

目录
相关文章
|
3月前
|
开发者
局部变量,在使用时再定义
关于局部变量,适时定义可以提高代码可读性并规避不必要的bug。示例代码中,为了避免误解`checkTaskApplyDTO`仅设置了`userId`,在`existAppliedTask`方法内部,可以通过将`checkTaskApplyDTO`的定义与设置属性的操作靠近,以明确其所有属性值的来源。 另外,本文还展示了一个因提前定义变量`ret`而导致的bug实例。如果将此变量的定义延迟至其实际使用前,则可以避免此类问题。适时定义变量有助于减少混淆,提高代码质量。
30 4
|
2月前
|
存储
全局变量和局部变量在堆和栈的区别
全局变量和局部变量在堆和栈的区别
143 0
|
3月前
成员变量、局部变量和静态变量的区别
成员变量、局部变量和静态变量的区别
21 0
|
5月前
初始化局部变量和全局变量
初始化局部变量和全局变量
42 0
|
存储 C语言 Perl
西门子S7-1200的变量如何使用?什么是局部变量和全局变量?临时变量和静态变量有什么区别?
今天给大家讲一下什么是局部变量、全局变量、临时变量、静态变量,这些变量都有什么区别,以及在西门子S7-1200中这些变量如何来使用。
西门子S7-1200的变量如何使用?什么是局部变量和全局变量?临时变量和静态变量有什么区别?
|
存储 C语言 C++
函数的内部处理及全局变量和局部变量
函数的内部处理及全局变量和局部变量
114 0
函数的内部处理及全局变量和局部变量
|
存储
局部变量和成员变量的4个区别
定义位置不同、内存中的位置不同、周期不同、初始化不同。
110 0
|
索引
访问局部变量
访问局部变量
95 0
|
人工智能 Java
变量的值传递,地址引用(和对象成员变量、局部变量创建和初始化的内存机制)
变量的值传递,地址引用(和对象成员变量、局部变量创建和初始化的内存机制)
171 0
变量的值传递,地址引用(和对象成员变量、局部变量创建和初始化的内存机制)