2009-10-27 4 views
74

나는 어딘가에 메모를 놓쳤다. 나는 이것을 설명해주기를 바란다.eigenclass가 self.class와 동일하지 않은 이유는 무엇입니까?

왜 객체의 고유 클래스가 self.class과 다른가요?

class Foo 
    def initialize(symbol) 
    eigenclass = class << self 
     self 
    end 
    eigenclass.class_eval do 
     attr_accessor symbol 
    end 
    end 
end 

class.self으로 eigenclass을 동일시 논리의 나의 기차는 오히려 간단하다

class << self는 클래스 메소드가 아닌 인스턴스 메소드를 선언하는 방법입니다. def Foo.bar의 바로 가기입니다.

따라서 클래스 개체에 대한 참조 내에서 self을 반환하는 것은 self.class과 동일해야합니다. 이는 class << self이 클래스 메소드/속성의 정의에 대해 selfFoo.class으로 설정하기 때문입니다.

그냥 혼란 스럽습니까? 아니면 Ruby 메타 프로그래밍에 대한 비열한 속임수입니까?

답변

106

class << self은 클래스 메소드를 선언하는 것 이상의 의미를 지닙니다.

class Foo 
    class << self 
    def a 
     print "I could also have been defined as def Foo.a." 
    end 
    end 
end 

이 작동하고, def Foo.a에 해당하지만, 그것이 작동하는 방식은 조금 미묘하다 : 아마 당신은 같은 일부 사용을 보았다. 비밀은 그 문맥에서 이 Foo 객체를 가리키며 그 클래스는 Class의 고유 한 익명 하위 클래스입니다. 이 하위 클래스는 Foo고유 클래스이라고합니다. 따라서 def a은 이라는 일반적인 메서드 호출 구문으로 액세스 할 수있는 Foo의 고유 클래스에 a이라는 새 메서드를 만듭니다.

이제 다른 예를 살펴 보자 : 처음에 이야기하기 어려울 수 있지만

str = "abc" 
other_str = "def" 

class << str 
    def frob 
    return self + "d" 
    end 
end 

print str.frob # => "abcd" 
print other_str.frob # => raises an exception, 'frob' is not defined on other_str 

이 예는, 마지막 동일합니다. String 클래스가 아니라 str의 고유 클래스에 String이라는 고유 한 익명 하위 클래스가 정의되어 있습니다. 이 정의되어 있습니다. 따라서 str에는 frob 방법이 있지만 일반적으로 String의 인스턴스는 그렇지 않습니다. 우리는 또한 String의 메소드를 오버라이드 할 수 있습니다 (까다로운 테스팅 시나리오에서는 매우 유용합니다).

이제는 원래 예제를 이해할 준비가되었습니다. 내부 Foo의 내부에서 self은 클래스 Foo이 아니라 인스턴스Foo 인 것을 나타냅니다. 그것의 고유 클래스는 Foo의 서브 클래스이지만, Foo이 아닙니다. 그렇지 않을 수도 있습니다. 그렇지 않으면 두 번째 예에서 본 트릭이 작동하지 않을 수 있습니다. 따라서 예제를 계속 진행하십시오.

f1 = Foo.new(:weasels) 
f2 = Foo.new(:monkeys) 

f1.weasels = 4 # Fine 
f2.monkeys = 5 # Also ok 
print(f1.monkeys) # Doesn't work, f1 doesn't have a 'monkeys' method. 

희망이 있습니다.

+0

그래서 다음 각 인스턴스가 생성 된 클래스의 익명의 하위 클래스에 미묘한을 설명 꽤 좋은 일을? –

+19

각 인스턴스의 * class *는 생성 된 클래스의 익명 하위 클래스입니다. f1의 클래스는 Foo의 익명 하위 클래스이고 Foo의 클래스는 Class의 익명 하위 클래스입니다. –

+4

멋진 답변 :) 많은 사람들이 당신만큼이나 분명히 이것을 이해하지 못합니다. – horseyguy

43

가장 간단한 대답은 고유 클래스를 인스턴스화 할 수 없습니다.

class F 
def eigen 
    class << self 
    self 
    end 
end 
end 
F.new.eigen.new #=> TypeError: can't create instance of virtual class 
+0

당신은이 웹 사이트에서 1 점 밖에 가질 수 없지만 당신과 당신의 스타일을 좋아합니다. – horseyguy

+0

동의/승무원 동의; 이것은 훌륭한 대답입니다. –

+1

흥미로운 정보이지만 질문에 대답하지 마십시오 – Alexey