2008-10-01 6 views
344

Ruby 메타 프로그래밍에 대한 내 머리를 들려주세요. mixin/modules은 항상 나를 혼란스럽게합니다.Ruby에서 포함과 확장의 차이점은 무엇입니까?

  • 포함 대상 클래스
  • 인스턴스 메소드으로 지정된 모듈 법 믹스 연장 : 믹스 지정된 모듈 방식의 대상 클래스 클래스 메소드

이렇게 큰 차이가 있습니까? 아니면 더 큰 용이 숨어 있습니까? 예 :

module ReusableModule 
    def module_method 
    puts "Module Method: Hi there!" 
    end 
end 

class ClassThatIncludes 
    include ReusableModule 
end 
class ClassThatExtends 
    extend ReusableModule 
end 

puts "Include" 
ClassThatIncludes.new.module_method  # "Module Method: Hi there!" 
puts "Extend" 
ClassThatExtends.module_method   # "Module Method: Hi there!" 
+0

다음 링크도 확인하십시오. http://juixe.com/techknow/index.php/2006/06/15/mixins-in-ruby/ – Donato

답변

209

당신이 말한 것은 정확합니다. 그러나 그것보다 더 많은 것이 있습니다.

Klazz에서 Mod 포함 클래스 Klazz 및 모듈 Mod가있는 경우 Mod의 방법에 Klazz 액세스의 인스턴스를 제공합니다. 또는 KlazzMod으로 확장하여 클래스KlazzMod의 방법으로 액세스 할 수 있습니다. 그러나 o.extend Mod으로 임의의 객체를 확장 할 수도 있습니다. 이 경우 o과 같은 클래스를 가진 다른 모든 객체가없는 경우에도 개별 객체는 Mod의 메소드를 가져옵니다.

13

맞습니다. 상수, 메소드를 추가

루비의 기본 구현은 , 그리고 모듈이 모듈의 변수 : 장면 뒤에

포함은 의 별칭이 (워드 프로세서)을 append_features 실제로 a 모듈이 인 경우이 모듈은 a 모듈 또는 그 조상 중 하나에 을 아직 추가하지 않았습니다.

274

extend - 지정된 모듈의 메소드와 상수를 대상의 메타 클래스 (즉 싱글 톤 클래스)에 추가합니다.

  • 당신이 Klazz.extend(Mod)를 호출하는 경우, 지금 Klazz는 (클래스 메소드)을 모의 방법
  • 지금 obj가 (예를 방법으로) 모의 방법을 가지고, obj.extend(Mod) 호출하는 경우가 있지만 obj.class의의 다른 인스턴스는 이러한 방법이 없습니다 덧붙였다.
  • extend

등 공공 방법 - 기본적으로 대상 모듈/클래스의 인스턴스 메소드로 지정된 모듈의 방법으로 혼합합니다. 예 :당신이 class Klazz; include Mod; end;를 호출하는 경우가 컨테이너 클래스/모듈 내에서 호출 할 의도 때문에

  • , 지금 Klazz의 모든 인스턴스는
  • include 개인 방법 (인스턴스 메소드 등) 모의 메소드에 액세스 할 수 있습니다.

그러나, 모듈 자주 원숭이 패칭 included 방법으로 재정include의 행동. 이것은 레거시 레일즈 코드에서 매우 두드러집니다. more details from Yehuda Katz. 기본 동작과 include에 대한

더 자세한 사항은, 당신은 문이 더있다 포함하지, 모 이미 Klazz에 포함되어있는 경우 다음 코드

class Klazz 
    include Mod 
end 
  • 을 실행, 또는 조상 한 한 가정하면 효과
  • 또한 Klazz의 Mod의 상수가 충돌하지 않는 한
  • Mod의 모듈 변수에 Klazz 액세스 권한을 부여합니다. 고리는
  • 호출자의 직계 선조 같이 모듈을 연결 포함있을 경우 @@foo 또는 @@bar
  • 가하면 ArgumentError 제기 (즉 그것은 모는 Klazz.ancestors에 추가하지만 모는 Klazz.superclass.superclass.superclass 체인에 추가되지 따라서 Klazz # foo에서 super을 호출하면 Mod # foo를 확인한 후 Klazz의 실제 수퍼 클래스의 foo 메소드를 확인합니다. 자세한 내용은 RubySpec을 참조하십시오.).

물론 the ruby core documentation은 항상 이러한 작업을 수행하는 가장 좋은 장소입니다. The RubySpec project은 기능을 정확하게 문서화했기 때문에 환상적인 리소스였습니다.

+13

나는 이것이 꽤 오래된 게시물이지만 회신의 명확성을 알고 있습니다. 덧글에서 나를 붙들 수 없었다. 좋은 설명을 해주셔서 고맙습니다. – MohamedSanaulla

+0

[RubySpec] (http://www.rubyspec.org/)이 사망했습니다. ( – wiseland

+0

@systho 이제는 링크가 작동하지 않습니다. – Anwar

4

모든 다른 답변

  • #append_featuresRubySpecrubydoc
  • 는 RubySpecs을 통해 발굴하기 위해 팁을 포함하여, 좋은 : 사용 사례에 관해서는

    https://github.com/rubyspec/rubyspec/blob/master/core/module/include_spec.rb

    https://github.com/rubyspec/rubyspec/blob/master/core/module/extend_object_spec.rb

    :

    하는 경우 너 에이 포함되어 있습니다.클래스 ReTableIncludes의 모듈 ReusableModule에서 메서드, 상수, 클래스, 하위 모듈 및 기타 선언이 참조됩니다.

    당신이 모듈 ReusableModule와 클래스 ClassThatExtends를 확장 경우

    는 다음 방법과 상수는 을 복사됩니다. 분명히주의하지 않으면 정의를 동적으로 복제하여 많은 메모리를 낭비 할 수 있습니다.

    ActiveSupport :: Concern을 사용하는 경우 .included() 기능을 사용하면 포함 된 클래스를 직접 다시 작성할 수 있습니다. ModuleClassMethods는 해당 클래스에 을 (복사 됨)으로 확장합니다.

    1

    전에 배웠지 만 사용해 볼 때 감사하겠습니다. 여기의 차이는 다음과 같습니다

    이 작동하지 않고 일하는 것이 내가 def page_views(campaign)로 정의 한 경우 :이 작동

    class UserAction 
        include Calculations 
    
        def self.page_views(campaign) 
        overall_profit = calculate_campaign_profit(campaign) 
        end 
    end 
    

    :

    class UserAction 
        extend Calculations 
    
        def self.page_views(campaign) 
        overall_profit = calculate_campaign_profit(campaign) 
        end 
    end 
    
    1

    나는 또한 설명하고 싶습니다 메커니즘이 작동합니다. 내가 옳지 않다면 올바르게 수정하십시오.

    우리는 include을 사용할 때 몇 가지 방법이 포함 된 모듈에 우리 클래스의 연결을 추가하고 있습니다.

    class A 
    include MyMOd 
    end 
    
    a = A.new 
    a.some_method 
    

    오브젝트에는 메소드가 없으며 clases 및 모듈 만 있습니다. 따라서 a이 메시지 some_method을 수신하면 a의 고유 클래스에서 검색 방법 some_method을 시작한 다음 A 클래스에서 시작하고 일부 (역순으로 마지막 포함 된 승리)가있는 경우 A 클래스 모듈에 연결됩니다.

    우리는 extend을 사용할 때 객체의 고유 클래스에있는 모듈에 연결을 추가하고 있습니다. 그렇다면 A.new.extend (MyMod)를 사용하면 모듈의 링크를 A의 인스턴스 고유 클래스 또는 a' 클래스에 추가합니다. 그리고 A.extend (MyMod)를 사용하면 A에 대한 연결을 추가합니다 (객체의 클래스도 객체 임). 고유 클래스 A'.

    다음 이렇게 a위한 방법 조회 경로는 다음과 같이 A =>은 또한 검색 경로 변경하는 앞에 추가 방법이

    클래스 => A. '=> 링크 모듈 (A)에'

    a => a '=> 앞에 붙은 모듈 A => A => A에 포함 된 모듈

    죄송합니다.

    관련 문제