是否有可能在Lua中复制Ruby的method_missing?

Wes*_*ham 6 syntax lua metaprogramming method-missing

我相当肯定,在Lua中,你可以使用一个给定的元表的__index,__newindex__call大致复制Ruby的method_missing.我有点:

function method_missing(selfs, func)

    local meta = getmetatable(selfs)
    local f
    if meta then
        f = meta.__index
    else
        meta = {}
        f = rawget
    end
    meta.__index = function(self, name)
        local v = f(self, name)
        if v then
            return v
        end

        local metahack = {
            __call = function(self, ...)
                return func(selfs, name, ...)
            end
        }
        return setmetatable({}, metahack)
    end

    setmetatable(selfs, meta)
end

_G:method_missing(function(self, name, ...)
    if name=="test_print" then
        print("Oh my lord, it's method missing!", ...)
    end
end)

test_print("I like me some method_missing abuse!")

print(this_should_be_nil)
Run Code Online (Sandbox Code Playgroud)

我的问题是:虽然语法类似,我当然可以使用它来复制功能,但它引入了一个突破性的错误.您在应用表的上下文中使用的每个变量method_missing永远不会为零,因为我必须返回一个可以被调用的对象,以便pass the buck从索引函数到实际调用的潜在调用.

ie在定义了如上所述的全局method_missing之后,尝试调用未定义的方法'test_print'按预期运行,但是当索引时test_print的值是非零的,而其他未响应的方法/变量,如this_should_be_nil非零值.

那么有可能避免这个陷阱吗?或者,如果不修改语言源本身,语法是否可以支持这种修改?我想象在Ruby中,索引和调用是如何类似的,而在Lua中它们是截然不同的.

cat*_*ell 2

你已经很好地识别了这个问题:据我所知,不可能用纯 Lua 来解决这个问题。

编辑:我错了,你可以通过使nil可调用。查看其他答案。在我看来,这仍然是一个坏主意。主要用例method_missing是代理对象,您可以通过另一种方式解决这个问题。method_missingKernel(Ruby)/ _G(Lua)上很糟糕:)

可以做的只是处理某些方法,例如,如果您知道您期望以以下方式开头的方法test_

local function is_handled(method_name)
    return method_name:sub(1,5) == "test_"
end

function method_missing(selfs, func)

    local meta = getmetatable(selfs)
    local f
    if meta then
        f = meta.__index
    else
        meta = {}
        f = rawget
    end
    meta.__index = function(self, name)
        local v = f(self, name)
        if v then
            return v
        end

        if is_handled(name) then
            local metahack = {
                __call = function(self, ...)
                    return func(selfs, name, ...)
                end
            }
            return setmetatable({}, metahack)
        end
    end

    setmetatable(selfs, meta)
end

_G:method_missing(function(self, name, ...)
    if name=="test_print" then
        print("Oh my lord, it's method missing!", ...)
    end
end)

test_print("I like me some method_missing abuse!")

print(this_should_be_nil)
Run Code Online (Sandbox Code Playgroud)

现在也许问题应该是:你为什么要复制method_missing,你能避免它吗?method_missing即使在 Ruby 中,也建议尽可能避免使用并首选动态方法生成。