6

__indexLua では、特定のメタテーブルの、__newindex、およびを使用して、 __callRuby の を大まかに複製できると確信しています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)

私の問題は次のとおりです。構文は似ており、機能を複製するために使用できますが、破壊エラーが発生します。インデックス関数から実際の呼び出しへの潜在的な呼び出しのmethod_missingために呼び出すことができるオブジェクトを返す必要があるため、適用するテーブルのコンテキストで使用するすべての変数は決して nil ではありません。pass the buck

つまり、上記のようにグローバルな method_missing を定義した後、未定義のメソッド 'test_print' を呼び出そうとすると、期待どおりに実行されますが、インデックスが作成されたときの test_print の値は非 nil であり、応答されない他のメソッド/変数this_should_be_nilは非 nil です。 .

では、この落とし穴を回避することは可能でしょうか? または、言語ソース自体を変更せずに、この変更をサポートするために構文を曲げることはできませんか? Ruby ではインデックス作成と呼び出しが類似しているのに対し、Lua ではそれらが異なるという点で困難が生じると思います。

4

3 に答える 3

1

だから@lhfからのヒントで、私は(私が知る限り)のまずまずの倍数を管理しましたmethod_missing。最終的に、私は以下を開発しました:

local field = '__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

        rawget(self, name)[field] = function(...)
            return func(self, name, ...)
        end
    end

    setmetatable(selfs, meta)
end

debug.setmetatable(nil, { __call = function(self, ...) 
    if self[field] then
        return self[field](...)
    end
    return nil
end, __index = function(self, name) 
    if name~=field then error("attempt to index a nil value") end
    return getmetatable(self)[field]
end, __newindex = function(self, name, value)
    if name~=field then error("attempt to index a nil value") end
    getmetatable(self)[field] = value
end} )

_G:method_missing(function(self, name, ...)
    local args = {...}
    if name=="test_print" then
        print("Oh my lord, it's method missing!", ...)
        return
    elseif args[1] and string.find(name, args[1]) then --If the first argument is in the name called... 
        table.remove(args, 1)
        return unpack(args)
    end
end)

test_print("I like me some method_missing abuse!")
test_print("Do it again!")

print(test_print, "method_missing magic!")
print(this_should_be_nil == nil, this_should_be_nil() == nil)

print(conditional_runs("runs", "conditionally", "due to args"))
print(conditional_runs("While this does nothing!")) --Apparently this doesn't print 'nil'... why?

出力:

Oh my lord, it's method missing!        I like me some method_missing abuse!
Oh my lord, it's method missing!        Do it again!
nil     method_missing magic!
true    true
conditionally   due to args

このスニペットを使用するmethod_missingと、Ruby とほぼ同じように使用できます (ただし、応答チェックは一切行われません)。それは、nil のメタテーブルを介して '責任を負わせる' ことを除いて、私の最初の応答に似ています。(ヒントをありがとう!) しかし、@greatwolf が言うように、Lua でこのような構成を使用する理由はおそらくないでしょう。同じダイナミズムは、おそらくより明確なメタメソッド操作によって実現できます。

于 2013-11-05T04:24:02.717 に答える