1

編集:明確にするために。これは、メタ プログラミングで何かを行う方法についての質問です。メモすることではありません。明らかに、メモ化するためのより良い方法があります。関連するメソッドには、その目的を説明するために「メモ化」が含まれています。


@foo私はメタプログラミングをいじっているだけなので、インスタンス変数を使用して答えないでください 。

実行中のメソッドからメソッド定義を上書きすることにより、インスタンスとクラスメソッドの両方をメモ化しようとする次のものがあります..

class Obj
  class << self

    def meta_me; self; end

    def class_memoize
      puts "hard core calculating ..."
      abc = "huge calculation result"

      raise "broken here with infinite loop"

      define_class_method "class_memoize" do
        puts abc
        abc
      end
      class_memoize
    end

    def define_class_method name, &blk
      meta_me.instance_eval do
        define_method name, &blk
      end
    end
  end

  def instance_memoize
    puts "hard core calculating ..."
    abc = "huge calculation result"

    self.class.meta_me.send :define_method, :instance_memoize do
      puts abc
      abc
    end

    instance_memoize
  end
end

o = Obj.new
o.instance_memoize
# hard core calculating ...
# huge calculation result

o.instance_memoize
# huge calculation result

インスタンス バージョンは機能しますが、クラス バージョンは機能しません。

参照用にクラス バージョンを試してみました。

4

1 に答える 1

1

倫理はさておき、思ったよりずっと簡単です。あなたの主な問題は、meta_me メソッドに間違ったものを使用していることです。これを試して:

class Object
  def metaclass
    class<<self;self;end
  end
end

これは、Ruby でメタプログラミングを行う場合によくあるモンキーパッチです。メソッドを動的に再実装するのは簡単です。

class Obj
  def self.class_memoize
    puts "calculating..."
    abc = "result"
    metaclass.send(:define_method, :class_memoize) do
      puts abc
      abc
    end
    class_memoize
  end

  def instance_memoize
    puts "calculating..."
    abc = "result"
    metaclass.send(:define_method, :instance_memoize) do
      puts abc
      abc
    end
    instance_memoize
  end
end

ご覧のとおり、メタクラス オブジェクトを取得したら、それがクラス メソッドであろうとインスタンス メソッドであろうと、同じ方法でメソッドを再定義します。メタクラス メソッドで名前空間全体を汚したくない場合は、class<<self;self;end参照したいときにいつでもイディオムを使用する方がよいでしょう。次のように、メソッドを直接呼び出すことができます。

(class<<self;self;end).send(:define_method, :foo){|bar| bar*23}

かっこは本当に必要ないことに注意してください。これは、むき出しのメタクラス参照である混乱を抑えるのに役立つだけです:)これが役に立てば幸いです。

于 2012-11-30T12:18:15.937 に答える