2010-06-13 4 views
4

입니다. 루비에서는 클래스 정의가 nil 인 이유는 무엇입니까? 메서드를 정의 할 때도 마찬가지입니다. nil으로 평가되는 이유는 무엇입니까? 클래스 정의가 클래스로 평가된다면 유용하지 않을까요? 지금 우리는 SomeClass.singleton_class를 사용할 수 있지만루비 : 클래스를 정의하는 대상은

답변

8

, 왜 정의 않는 클래스 평가 :

Foo = someclass

그래서 지금 당신은 클래스의 인스턴스를 다음 중 하나를 수행 할 수 있습니다?

아니요.

먼저 Ruby에서 클래스를 정의하지 않으면 클래스 본문을 실행합니다. 둘째, 클래스 본체를 실행하면 이 아닌nil으로 평가되며, 클래스 본문의 마지막 표현식의 값으로 평가됩니다. 이것은 모듈 본문을 실행하고 메소드 본문을 실행하는 것과 완벽하게 일치합니다.

참조, 예를 들면 : 왜 nil로 평가 않습니다 같은

class Foo 
    'Hello' 
end 
# => 'Hello' 

는 방법을 정의 간다?

실제로는 그렇지 않습니다. 메소드 정의는 구현 정의 값으로 평가됩니다. 구현 정의 값으로 평가하는 이유는 지금까지 루비 커뮤니티가 반환해야 할 것에 대한 합의에 도달하지 못했기 때문입니다.

그 방법에 해당하는 CompiledMethod 개체로 평가해야한다고 주장하는 사람들도 있습니다. Rubinius가하는 일입니다. 그러나 여기에는 문제가 있습니다. 모든 Ruby 구현이 메소드를 컴파일하는 것은 아닙니다. 그리고 그들 모두가 을 수행하지 않고을 컴파일하고 정의 시간에 컴파일하십시오.예를 들어, JRuby는 실행될 때만 컴파일합니다.보다 정확하게는 이후에 20 번 실행되었습니다. 경우에 따라 을 모두으로 컴파일하지 않는 경우가 있습니다 (예 : Google App Engine과 같이 컴파일이 금지 된 환경). 또한 모든 Ruby 구현에 컴파일 된 메소드에 대한 Ruby 표현이있는 것은 아닙니다. Rubinius의 컴파일 된 메소드는 Rubinius 바이트 코드이고, YARV의 컴파일 된 메소드는 YARV 바이트 코드이며, JRuby의 컴파일 된 메소드는 JVM 바이트 코드이며, IronRuby의 컴파일 된 메소드는 DLR 트리입니다. 물론 가장 널리 사용되는 구현 인 MRI는 심지어 컴파일러가 없습니다.

다른 말로하면 해당 메서드에 해당하는 UnboundMethod 개체로 평가해야합니다. 여기서 문제는 메서드에 해당하는 단일 UnboundMethod 개체가 없다는 것입니다. 무한히 많은 사람들이 있습니다. Ruby 메서드 개체가 아닙니다. 이 개체로 변환 된 일 수 있지만 개체 자체는 아닙니다. 객체로 변환되면 매번 새로운 객체가 생성됩니다. 따라서 반환 된 UnboundMethod 개체는 실제로 정의 된 메서드와 직접 관련이 없습니다. 또한 언 바운드 방식으로 무엇을하고 싶습니까? I 언 바운드 메서드를 사용하는 유일한 경우는 수정할 수없는 이미 존재하는 메서드를 래핑하는 것입니다. 하지만 어쨌든 정의에 액세스 할 수 있다면 랩핑 할 필요가 없습니다.

세 번째 그룹은 메서드 정의가 해당 이름으로 평가되어야한다고 말합니다. 이것은 다소 자의적인 선택 인 것으로 보인다. 사실, 이것이 왜 그렇게되어야하는지에 대한 어떤 설득력있는 이유도 보지 못했습니다.

# here's how you make a single method private today 
def foo(bar) end 
private :foo 

# instead you could do this: 
private def foo(bar) end 

그래서, 기본적으로, 이유는 왜 메소드 정의는 (대부분의 구현에있는 단지 nil입니다) 구현 정의 된 값을 반환한다 : 말 그대로 유일한 인수는이 루비보다 자바처럼 보이게 할 수 있도록 할 것입니다 아무도 더 나은 제안을 내놓지 않았습니다.

흥미롭게도 Module#define_method이 유용합니다. 메서드를 사용하여 메서드를 정의하면 이전 메서드가 반환됩니다. proc을 사용하여 메소드를 정의하면 해당 proc의 변형을 리턴합니다. 블록을 사용하여 메소드를 정의하면 해당 블록에 해당하는 proc을 리턴합니다.

class Foo 
    $bar = ->{} 
    $baz = define_method :baz, $bar 

    $qux = instance_method :baz 
    $quux = define_method :quux, $qux 

    define_method :corge do;end 
end 
# => #<Proc:[email protected](irb):8 (lambda)> 

$bar.eql? $baz # => true 
$bar.equal? $baz # => false 
$qux.equal? $quux # => true 

는이 클래스로 평가하는 것이다 클래스를 정의하면 유용하지 않을까요 : 즉, 메소드 본문에 해당하는 실행 가능한 객체를 반환?

왜? 지금은 클래스 몸체가 원하는 모든 것을 반환 할 수 있습니다. 클래스를 포함합니다. 당신의 제안에 따라, 그것은 클래스를 반환 할 수 있으므로 엄격하게 덜 강력합니다.

foo = Object.new 
foo_singleton_class = class << foo; self end 

또는 더 잘을 :

또한, 유일한 경우는 내가 클래스 본문은 클래스 자체를 반환 할 필요했다,이 같은 객체의 싱글 톤 클래스에 대한 참조를 얻기 위해이었다 알려진 패턴 :

class Object; def singleton_class; class << self; self end end end 

그러나 지금 Object#singleton_class 핵심 라이브러리의 일부, 즉 더 이상 필요하지 않습니다.

+0

훌륭한 답변 (평소와 같이! :-) –

+0

철저한 검토에 감사드립니다. 특히 편하게 느끼지는 않는 몇 가지 사항이 있지만 정치적이며 관련 메일 링리스트에 더 적합 할 것입니다. 그러나 여기서 컨센서스를 제시하는 것이 얼마나 사소한 지 알 수 있습니다. 감사! – wilhelmtell

3

nil로 평가하지 않는 클래스를 정의, 그것은

class X 
    2 
end # => 2 

전형적인 예는 singleton = class << SomeClass; self; end입니다 (메소드를 호출처럼) 마지막 표현이었다 무엇이든 반환합니다.

메서드 정의는 nil을 반환합니다. 따라서 메서드 정의로 끝나는 클래스는 nil을 반환합니다. 메소드 정의가 무엇을 반환하고 싶습니까? 언제 유용할까요? 당신은 클래스가 반환 할 경우

, 그것은 self로 끝 쉽다 :

class X 
    def foo 
    :bar 
    end 

    self 
end # => X 
+0

'class X; def f; 2; 종료; end # => nil' – wilhelmtell

+0

실제로'def '가'nil'을 리턴하기 때문입니다. 내 편집 된 답변보기 –

+0

Thanks @ March-André! – wilhelmtell

1

당신이 Class.new {...} 대신에 class 키워드를 사용하여 호출하여 그 기능을 달성 할 수있다.

someclass = Class.new{ 
    def bar 
    puts "baz" 
    end 
}

다음 클래스 var에 상수를 할당하여 클래스의 이름을 지정할 수 있습니다. nil에 루비에서

instance1 = someclass.new 
instance2 = Foo.new 

instance1.bar #=> baz 
instance2.bar #=> baz 
+0

우는 이것에 대해 생각하지 않았다! 감사합니다 Derick! – wilhelmtell

관련 문제