【问题标题】:Lua strange behaviour with _ENV_ENV 的 Lua 奇怪行为
【发布时间】:2018-11-25 05:14:03
【问题描述】:

谁能解释一下为什么 lua 5.3.5 会这样?

a="global"
local b="local"

function problem(_ENV)
    a="fn_a"
    b="fn_b"
end

problem{}
print(_VERSION)
print("a",a)
print("b",b)

--[[ https://www.lua.org/cgi-bin/demo output:
Lua 5.3
a       global
b       fn_b
]]

为什么改变_ENV后局部变量可以改变?是错误还是功能?

【问题讨论】:

  • 粗略地说,locals 优先于 upvalues,upvalues 优先于 globals。
  • 本地人不在环境中;它们在块(编译单元)中。所以,这是一个功能。
  • 如果您尝试使用用户提供的代码,请研究Lua sandboxing
  • 沙盒也有同样的问题 local b a="global" b="local" function fn() a="fn_a" b="fn_b" end print(a,b) run_sandbox(sandbox_env,fn ) 打印(a,b)

标签: lua


【解决方案1】:

问:如何消除所有上值?
答:

a="global"
local b="local"

-- load() actually eliminates all upvalues :-)
no_problem = assert(load[[
    return function (_ENV)
        a="fn_a"
        b="fn_b"
    end
]])()

no_problem{}
print(_VERSION)
print("a",a)  -->  a    global
print("b",b)  -->  b    local

【讨论】:

  • 它仅在加载块内照亮上值,但如果我从加载块调用其他函数,行为将是相同的。它可以修改父母状态。所以只有创建不同lua上下文的io.popen或特殊c函数才能真正分离代码。
  • @SergeyKovalev - 您可以在另一个 load 块中使用 load 块;-)
【解决方案2】:

您正在使用以下代码创建upvalue

local b="local"
function problem(_ENV)
    b="fn_b"
end

在函数解释器的解析过程中检测到,该函数引用来自函数内可见的包含范围之一的局部变量,因此直接链接它。对局部变量的访问先于在_ENV 中查找全局变量。如果你在函数定义后加上local b="local",它不会被函数调用改变。

【讨论】:

  • 如何消除所有的upvalues?
  • @SergeyKovalev Upvalues 不能被“消除”。只是不要引用它们。
猜你喜欢
  • 1970-01-01
  • 2014-04-02
  • 1970-01-01
  • 1970-01-01
  • 2016-03-03
  • 2013-09-05
  • 2015-06-28
  • 2020-11-17
  • 2020-03-02
相关资源
最近更新 更多