【问题标题】:How to run a string and get a table that has all the variables that the code created in lua?如何运行一个字符串并获得一个包含代码在 lua 中创建的所有变量的表?
【发布时间】:2021-08-16 23:41:09
【问题描述】:

所以我正在为 LIKO-12 制​​作自己的操作系统,我需要运行 .lk12 文件,但我需要一个函数来运行字符串作为代码并返回一个包含代码创建的所有变量的表

例子:

function foo()
        return "Hello,"
end

function bar()
        return " World!"
end

hello = foo()..bar()

应该返回一个包含 2 个函数的表: 一个名为 foo 的函数,它返回“Hello” 一个名为 bar 的函数,它返回“World!” 和一个名为 hello 的变量,它有“Hello, World!”

您应该能够使用以下代码从代码中调用函数 vars["foo"]()vars.foo()

谁能帮帮我?

【问题讨论】:

  • 所以你是说hello 在做hello = foo()..bar() 之后应该有一个具有2 个功能的表吗?
  • foo() 和 bar() 返回字符串,.. 运算符连接 2 个字符串,将它们加在一起,所以 hello 应该是“Hello, World!”
  • 那你想要什么?什么“应该返回一个有 2 个函数的表”?

标签: lua


【解决方案1】:

当您创建或使用全局变量时,它实际上存储在名为“环境”的表中,或 _ENV(它不是全局的,它是您自动获得的局部变量)

所以你的代码:

function foo()
        return "Hello,"
end

function bar()
        return " World!"
end

hello = foo()..bar()

真的在做:

function _ENV.foo()
        return "Hello,"
end

function _ENV.bar()
        return " World!"
end

_ENV.hello = _ENV.foo().._ENV.bar()

所以如果我们只是将_ENV 设置为一个新表并将其返回,那么这正是您想要的表。您可以通过将load(这是您运行字符串的方式)作为第四个参数传递来执行此操作。这个函数会这样做:

function loadAndReturnEnv(codeString)
    local env = {}
    load(codeString, nil, nil, env)() -- error checking skipped for demonstration
    return env
end

但是,请注意,所有常见的全局内容,例如 string.reptable.sortloadprint,在这个新的 _ENV 中都不存在。如果这就是你想要的,那就太好了。但我猜你可能确实想要它们。在这种情况下,我们可以使用元表 __index 功能,这样如果代码在其 _ENV 中查找某些内容但它不存在,则它会在我们(调用者的)_ENV 中查找。

function loadAndReturnEnvWithGlobals(codeString)
    -- note: env is the environment for the code we're about to run
    -- (which will be called _ENV in that code), and _ENV is the environment
    -- of the loadAndReturnEnvWithGlobals function (i.e. the "real" environment)
    local env = {}
    setmetatable(env, {__index=_ENV})
    load(codeString, nil, nil, env)() -- error checking skipped for demonstration
    setmetatable(env, nil) -- set the table back to normal before we return it
    return env
end

但是等等...程序现在可以在运行时调用print,但是如果它定义了一个函数,则该函数不能调用print,因为我们在代码之后删除了返回真实环境的链接回来。所以我认为解决这个问题的最好方法是让环境保持链接,然后复制函数等。

function loadAndReturnEnvWithGlobals2(codeString)
    local env = {}
    setmetatable(env, {__index=_ENV})
    load(codeString, nil, nil, env)() -- error checking skipped for demonstration

    local result = {}
    for k,v in pairs(env) do result[k]=v end
    return result
end

虽然这会复制值,所以如果您有任何更改变量的函数,您将不会看到更改的变量。

您使用哪个版本取决于您。它们各有优缺点。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-12-30
    • 2020-04-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多