문제

특정 객체에 싱글 톤 방법을 추가하고 싶습니다. 객체의 인스턴스 메소드가 먼저 호출되면 일부 작업을 수행 한 다음 같은 이름의 상기 객체 (작업이 포함 된)에 대한 싱글 톤 메소드를 생성하기를 바랍니다. 상기 객체의 모든 후속 호출에서 싱글 톤 메소드는 인스턴스 방법을 섀도 롭게하고 호출됩니다.

싱글 톤 방법을 만드는 방법을 알고 있습니다. 내 문제는 람다를 호출하기 위해 생성 된 싱글 톤 방법을 원한다는 것입니다.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()

실행할 때 다음과 같은 결과를 제공합니다.

나는 모든 것에 대해 말하고, 나는 수업 방법이다

이것은 객체 #thing : 0x1d204로 참조 된 인스턴스 메소드입니다.

이것은 객체 #thing : 0x1d1dc>에 의해 참조 된 인스턴스 메소드입니다.

이것은 Thing Object #thing : 0x1d204의 싱글 톤 방법입니다.

이것은 객체 #thing : 0x1d1dc>의 싱글 톤 메소드입니다.

도움이 되었습니까?

해결책

블록을 사용하여 메소드를 정의 할 수 있습니다 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

다음은 a의 구현입니다 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

다른 팁

이제 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

글쎄, 그것을하는 한 가지 방법은 인스턴스 변수로 포장하는 것입니다.

(FYI 당신은 할 수 있습니다 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 여전히 원래 정의가 있습니다.

대안은 척이 지적한 바와 같이 인스턴스와 관련된 싱글 톤 클래스 (일명 메타 클라스, 일명 고유 한)를 사용하는 것입니다. 싱글 톤 클래스는 객체와 관련된 모든 싱글 톤 방법을 저장하는 객체입니다. Funny를 사용하여 싱글 톤 수업 평가의 컨텍스트를 얻을 수 있습니다. 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
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top