gpt4 book ai didi

debugging - 从协程内省(introspection) _ENV

转载 作者:行者123 更新时间:2023-12-02 00:51:34 24 4
gpt4 key购买 nike

注意:我使用的是 Lua 5.3 版。


这个问题是由 Programming in Lua(第 4 版)的练习 25.1(第 264 页)提出的。该练习内容如下:

Exercise 25.1: Adapt getvarvalue (Listing 25.1) to work with different coroutines (like the functions from the debug library).

练习中引用的函数 getvarvalue 逐字复制如下。

-- Listing 25.1 (p. 256) of *Programming in Lua* (4th ed.)

function getvarvalue (name, level, isenv)
local value
local found = false

level = (level or 1) + 1

-- try local variables
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

-- try non-local variables
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 -- avoid loop

-- not found; get value from the environment
local _, env = getvarvalue("_ENV", level, true)
if env then
return "global", env[name]
else -- no _ENV available
return "noenv"
end

end

下面是我对该函数的增强版本,它实现了练习中指定的附加功能。这个版本接受一个可选的 thread 参数,应该是一个协程。此增强版本与原始 getvarvalue 之间的唯一区别是:

  1. 处理额外的可选thread参数;
  2. level参数的特殊设置取决于thread参数是否与正在运行的协程相同;和
  3. 在调用 debug.getlocaldebug.getinfo 以及递归调用中传递 thread 参数。<

(我在源代码中通过编号注释标出了这些差异。)

function getvarvalue_enhanced (thread, name, level, isenv)
-- 1
if type(thread) ~= "thread" then
-- (thread, name, level, isenv)
-- (name, level, isenv)
isenv = level
level = name
name = thread
thread = coroutine.running()
end

local value
local found = false

-- 2
level = level or 1
if thread == coroutine.running() then
level = level + 1
end

-- try local variables
for i = 1, math.huge do
local n, v = debug.getlocal(thread, level, i) -- 3
if not n then break end
if n == name then
value = v
found = true
end
end
if found then return "local", value end

-- try non-local variables
local func = debug.getinfo(thread, level, "f").func -- 3
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 -- avoid loop

-- not found; get value from the environment
local _, env = getvarvalue_enhanced(thread, "_ENV", level, true) -- 3
if env then
return "global", env[name]
else
return "noenv"
end

end

这个函数工作得相当好,但我发现了一个奇怪的情况1,它失败了。下面的函数 make_nasty 生成一个协程,其中 getvarvalue_enhanced 找不到 _ENV 变量;即它返回 "noenv"。 (作为 nasty 基础的函数是闭包 closure_B,它又调用闭包 closure_A。它是 closure_A 然后产生。)

function make_nasty ()
local function closure_A () coroutine.yield() end
local function closure_B ()
closure_A()
end

local thread = coroutine.create(closure_B)
coroutine.resume(thread)
return thread
end

nasty = make_nasty()
print(getvarvalue_enhanced(nasty, "_ENV", 2))
-- noenv

相比之下,几乎相同的函数 make_nice 生成一个协程,getvarvalue_enhanced 成功找到一个 _ENV 变量。

function make_nice ()
local function closure_A () coroutine.yield() end
local function closure_B ()
local _ = one_very_much_non_existent_global_variable -- only difference!
closure_A()
end

local thread = coroutine.create(closure_B)
coroutine.resume(thread)
return thread
end

nice = make_nice()
print(getvarvalue_enhanced(nice, "_ENV", 2))
-- upvalue table: 0x558a2633c930

make_nastymake_nice 之间的唯一区别是,在后者中,闭包 closure_B 引用了一个不存在的全局变量(并且什么都不做)。

问: 我如何修改 getvarvalue_enhanced 以便它能够为 nasty 定位 _ENV,它对 nice 的作用是什么?


编辑:更改了 make_nastymake_nice 中闭包的名称。


EDIT2:练习 25.3(同一页)的措辞可能与此处相关(我强调):

Exercise 25.3: Write a version of getvarvalue (Listing 25.1) that returns a table with all variables that are visible at the calling function. (The returned table should not include environmental variables; instead it should inherit them from the original environment.)

这个问题意味着应该有一种方法可以从函数中获取仅仅可见的变量,无论函数是否使用它们。这样的变量肯定会包括 _ENV。 (作者是Lua的创造者之一,所以他知道他在说什么。)


1 我敢肯定,对这个示例中发生的事情有更好理解的人将能够想出一种不太复杂的方法来引发相同的行为。我在这里展示的例子是我偶然发现的情况所能想到的最简单的形式。

最佳答案

  local function inner_closure () coroutine.yield() end
local function outer_closure ()
inner_closure()
end

The function make_nasty below generates a coroutine for which getvarvalue_enhanced fails to find an _ENV variable; i.e. it returns "noenv"

这是正确的行为。
闭包 outer_closure 具有上值 inner_closure 但没有上值 _ENV
这就是词法作用域的工作原理。
一些闭包没有 _ENV 上值也没关系。

在您的示例中,闭包 inner_closure 未在 outer_closure 的主体内定义。
inner_closure 未嵌套在 outer_closure 中。

关于debugging - 从协程内省(introspection) _ENV,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57161334/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com