【问题标题】:quoting troubles in Lua引用 Lua 中的问题
【发布时间】:2016-10-28 08:22:22
【问题描述】:

我正在尝试在 lua 中创建一个引号函数,因此我可以将参数用作字符串但不带引号或在某些环境中访问它们。很像this question的第二条评论

w = print
function test()
   local function _ix( _ , k )
w( "              _ix \\ " , _ , k )
            local v = rawget( _G , k )
w( "              <-- " , k )
         return k
         end
  local _ = setmetatable( {} , { __index = _ix } )
  local function q( _ )    return _  end
        q = setfenv( q , _ )
return q
end

所以,当我运行它时:

q = test()
w( "q( uno )" , q( uno ) )

它甚至不调用 __index 元方法:

---------- Capture Output ----------

q( uno )    nil

> Terminated with exit code 0.

那么,我做错了什么?

【问题讨论】:

  • 从使用合理的变量名、格式和较少的自诱导间接开始。
  • @oka 我做了一个编辑,使代码尽可能地可读。一旦它在全球范围内应用,它应该更容易阅读。
  • @warspyking 您的编辑与原始代码有明显冲突。您可以像this 一样重写原始内容,但这仍然是荒谬的,因为它试图以错误的顺序查找内容。请参阅下面的答案。

标签: lua


【解决方案1】:

如果我理解正确,那么您尝试做的事情就没有多大意义。 uno 将在 q 被称为 in 而不是 with 的环境中查找。在您的示例中,这就像调用q(nil)。另一个问题中的示例之所以有效,是因为它们在相同的全球环境中工作。

您可以使用编写一个辅助函数来拦截您当前的环境nil-lookups,但必须在您想要使用这些nil-to-string 查找的任何环境中抢先调用它。

local function intercept (tab)
    setfenv(2, setmetatable(tab or {}, {
        __index = function (_, key)
            return key
        end
    }))
end

而且您需要一个环境克隆功能,除非您想每次都手动创建沙箱,否则您可能会弄乱父环境(例如,_G)。您可以将这个逻辑移到 intercept 内部以获得更简洁的函数调用,但灵活性较低。

local function clone_current_env ()
    local env = {}

    for key, value in pairs(getfenv(2)) do
        env[key] = value
    end

    return env
end

将它们一起使用,您可以在您所处的任何环境中将nil 查找变成字符串。

intercept(clone_current_env())
print(type(foo), type(bar)) --> string string

这是一些元编程,我真的不知道为什么你会想要编写这样的代码,除非作为概念证明。 p>


一个完整的例子。

DEMO

local function clone (tab)
    local new = {}

    for key, value in pairs(tab) do
        new[key] = value
    end

    return new
end

local function enable_nil_strings ()
    setfenv(2, setmetatable(clone(getfenv(2)), {
        __index = function (env, key)
            return key
        end 
    }))
end

local function disable_nil_strings()
    setmetatable(getfenv(2), nil)
end

-----------------------------------------------------

print(type(foo), type(bar)) --> nil nil
enable_nil_strings()
print(type(foo), type(bar)) --> string string
disable_nil_strings()
print(type(foo), type(bar)) --> nil nil

最后,可以说实现这一点的最佳方式是简单地环绕执行上下文:

local function with_nil_strings (context, ...)
    local env = {}

    for key, value in pairs(getfenv(2)) do
        env[key] = value
    end

    setfenv(
        context,
        setmetatable(env, {
            __index = function (_, key) return key end 
        })
    )

    context(...)
end

print(type(foo)) --> nil

with_nil_strings(function ()
    print(type(foo)) --> string
end)

print(type(foo)) --> nil

【讨论】:

    猜你喜欢
    • 2013-09-17
    • 2021-07-01
    • 2016-12-21
    • 2011-11-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-06-06
    • 2021-02-01
    相关资源
    最近更新 更多