2

私は次のクラスを持っています

local PROGRESS = {}

PROGRESS.__index = function(self,key)

    if key~="__group" and self.__group[key] then 
        return  self.__group[key]           
    else 
        return rawget(self,key)
    end 
end 

これが行うことは、アクセスすると(別のクラスのオブジェクトである)でtable[key]ルックアップを実行し、nilでない場合はを返します。table.__grouptable.__group[key]

今、私はメンバー関数に対して同じことをしようとしています。つまりtable:key() 、ルックアップを呼び出す場合はで実行する必要がありtable.__group、関数が存在する場合は、を呼び出す必要がありtable.__group:key()ます。

どうすればこれを達成できますか?

私はこれをやろうとしました。

local PROGRESS = {}

    PROGRESS.__index = function(self,key)

       if key~="__group" and self.__group[key] then 


         local val = self.__group[key]
         if type(val) == "function" then 
             self.__group:val()
             return function() end 
         end


         return  self.__group[key]          
       else 
         return rawget(self,key)
       end 
    end 

しかし、ここには2つの問題があります。

  1. 元の関数の引数を取得できません
  2. イベントtable[key].functionを呼び出さずにアクセスするだけで、関数が呼び出されます

そして、私は物事を複雑にしようとしていると感じており、解決策ははるかに簡単です。

どんな助けでも大歓迎です。

アップデート

@Mud元のコードの問題は、メンバー関数に「self」として渡されたオブジェクトが新しいクラスのオブジェクトであるということです。古いクラスではありません。

このコードを検討してください

GROUP_CLASS = {}
GROUP_CLASS.__index = GROUP_CLASS
function GROUP_CLASS:showSum    (a,b) print(self);print(a + b) end


group_object = setmetatable({},GROUP_CLASS)
group_object:showSum(1,2)





local PROGRESS_CLASS = {}
PROGRESS_CLASS.__index = function(self,key,value)
    if key~="__group" and self.__group[key] then 
        return self.__group[key]
    else 
        return rawget(self,key)
    end 
end 



progress_object = setmetatable( {__group = group_object} , PROGRESS_CLASS)
progress_object:showSum(3,3) 
--progress_object is passed as first argument to showSum.  But i need group_object to be passed

上記のコードで、When progress_object:showSum(3,3)が呼び出されると、progress_objectの代わりにgroup_object(つまりprogress_object .__ group)をselfとして渡すことができますか。

それが理にかなっていることを願っています。

4

1 に答える 1

6

更新された投稿への応答:

progress_objectは、showSumの最初の引数として渡されます。しかし、group_objectを渡す必要があります

メソッドが呼び出されたオブジェクトの状態を無視し、他のオブジェクトの状態に置き換える場合、なぜそのオブジェクトのメソッドでさえあるのでしょうか。これは、加算演算子をオーバーライドして乗算を行うようなもので、混乱のレシピです。

言い換えれば、あなたはこれが欲しいです:

progress_object:method("foo")

奇妙な内部機構を介して、これに解決するには:

group_object:method("foo")

ステップをスキップして、後者の呼び出しを行ってみませんか?

必要な場合は、次のように置き換えるメソッドのプロキシを返すことでこれを実現できますself__group

local PROGRESS_CLASS = {}
PROGRESS_CLASS.__index = function(self,key)
  local groupval = self.__group[key]
  if key == '__group' or not groupval then
    return rawget(self,key)
  elseif type(groupval) ~= 'function' then
    return groupval
  else
      return function(...)
        if self == ... then -- method call
          -- replace self argument with __group
          return groupval(self.__group,select(2,...))
        else
          return groupval(...)
        end
      end
  end
end

元の投稿への応答:

メンバー関数に対して同じことをしようとしている方法。つまり table:key()、ルックアップを呼び出す場合はで実行する必要がありtable.__group、関数が存在する場合は、を呼び出す必要がありtable.__group:key()ます。

どうすればこれを達成できますか?

何もしない。元のコードがこれを処理します。

Luaは「メンバー関数」が何であるかを知りません。メンバーはメンバー(つまり、テーブル内の要素)であり、そのメンバーのが関数であるかどうかは関係ありません。

覚えて:

  1. obj:method(a,b,c)とまったく同じですobj.method(obj,a,b,c)
  2. obj.methodとまったく同じobj["method"]です。
  3. あなたのコードはすでに解決obj["method"]されていますobj.__group["method"]

これで完了です。

たとえば、次のようになります。

group = {}
function group:showSum    (a,b) print(a + b) end
function group:showProduct(a,b) print(a * b) end

最初のコードを使用して、次のように記述できます。

foo = setmetatable({__group = group}, PROGRESS)

foo:showSum(3,3) -- 6
foo:showProduct(3,3) -- 9

それでおしまい。



ここにいる限り、2番目の関数が何をしているのか見てみましょう。

     local val = self.__group[key]
     if type(val) == "function" then 
         self.__group:val()
         return function() end 
     end

まず、から関数値を取得します__group。この時点で完了です。その値を返すだけで、呼び出し元はその値を呼び出します(つまり(...))。代わりに、 (key == "val"でない限り)__group["val"]まったく異なる関数である可能性が高い関数__group[key]を呼び出してから、呼び出し元に何もしない関数を渡します。

于 2012-06-27T22:53:49.493 に答える