2

特定のオブジェクトにシングルトン メソッドを追加したいと考えています。オブジェクトのインスタンスメソッドが最初に呼び出されたときに、何らかの作業を行い、同じ名前のオブジェクト (作業を含む) のシングルトンメソッドを作成することを望みます。このオブジェクトに対する後続のすべての呼び出しでは、シングルトン メソッドがインスタンス メソッドをシャドウして呼び出されます。

私はシングルトンメソッドを作成する方法を知っています.私の問題は、ラムダを呼び出すために作成されたシングルトンメソッドが欲しいということです(lこの場合)。def はクロージャーを作成しないため、メソッドが後で呼び出されるときに変数 l (以下のコード) を参照できません (l.call()この例ではコメントアウトされています) 特定のオブジェクトでシングルトン メソッドを作成するときにクロージャーを作成する方法を知りたいです. どんな助けでも大歓迎です。ありがとうございました。

class Thing
end

t = Thing.new
t2 = Thing.new

Thing.instance_eval() do
  def speak
    puts "I speak for all Things, I am a class method"
  end
end

Thing.class_eval() do
  def speak
    puts "This is the instance method referenced by the Thing object #{self}"
    r = "something I wish to hold on to, maybe expensive to calculate"
    l = lambda {puts r}
    instance_eval() do
      def speak()
        puts "This is the singleton method in the Thing object #{self}"
        #l.call() # I want this to work! How?
      end
    end
  end
end

Thing.speak()
t.speak()
t2.speak()
t.speak()
t2.speak()

実行すると、次の結果が得られます: (「<」を「#」に変更して、html に表示されるようにしました)

私はすべてのものを代弁します、私はクラスメソッドです

これは Thing オブジェクトによって参照されるインスタンス メソッドです #Thing:0x1d204>

これは Thing オブジェクトによって参照されるインスタンス メソッドです #Thing:0x1d1dc>

これは Thing オブジェクトのシングルトン メソッドです #Thing:0x1d204>

これは Thing オブジェクトの singleton メソッドです #Thing:0x1d1dc>

4

3 に答える 3

2

を使用してブロックでメソッドを定義できますdefine_method

例:

class Object
  def eigenclass
    class <<self; self end
  end
end

a = "Hello"
other_word = "World"
a.eigenclass.class_eval do
  define_method(:cliche) {"#{self} #{other_word}"}
end
a.cliche # => "Hello World"
"Goodbye".cliche # => NoMethodError: undefined method `cliche' for "Goodbye":String

define_singleton_methodメソッドの実装は次のとおりです。

class Object
  def define_singleton_method(name, &block)
    eigenclass = class<<self; self end
    eigenclass.class_eval {define_method name, block}
  end
end
于 2009-07-17T01:05:41.670 に答える
2

1.9 がリリースされたので、define_singleton_method を使用できます。

jruby --1.9 -S irb
irb(main):019:0> fn = -> { length * 10 }
=> #<Proc:0x77cb8e0f@(irb):19 (lambda)>
irb(main):020:0> s.define_singleton_method :length_times_ten, fn
=> #<Proc:0x77cb8e0f@(irb):19 (lambda)>
irb(main):021:0> s
=> "a string"
irb(main):022:0> s.length_times_ten
=> 80
于 2011-03-18T23:18:42.807 に答える
1

それを行う 1 つの方法は、インスタンス変数にパックすることです。

class Thing(参考までに、もう一度開くだけですThing(を使用するよりも少し短く、メソッド内からメソッドを定義する#class_eval必要はありません)。#instance_eval

class Thing
  def speak
    puts "This is the instance method referenced by the Thing object #{self}"
    r = "something I wish to hold on to, maybe expensive to calculate"
    @l = lambda {puts r}
    instance_eval do 
      def speak()
        puts "This is the singleton method in the Thing object #{self}"
        @l[]
      end
    end
  end
end

これは を再定義#speakしますが、 のそのインスタンスに対してのみですThing。の他のインスタンスはThing元の定義のままです。

別の方法は、Chuck が指摘したように、インスタンスに関連付けられたシングルトン クラス (別名メタクラス、別名固有クラス) を使用することです。シングルトン クラスは、オブジェクトに関連付けられたすべてのシングルトン メソッドを格納するオブジェクトです。変な構文 (通常のクラスによってclass <<object ; ... ; end与えられるコンテキストと同様) を使用して、シングルトン クラス評価のコンテキストを取得できます。#class_eval

class Thing
  def speak
    puts "This is the instance method referenced by the Thing object #{self}"
    r = "something I wish to hold on to, maybe expensive to calculate"
    singleton_class = class <<self # open singleton class context for current instance
      # in this context, self now refers to the singleton class itself
      self
    end
    l = lambda {puts r}
    singleton_class.class_eval do
      # since we used #class_eval, local variables are still in scope
      define_method(:speak) do 
        puts "This is the singleton method in the Thing object #{self}"
        # since we used #define_method, local variables are still in scope
        l[]
      end
    end
  end
end
于 2009-07-17T21:47:45.780 に答える