루비 메타 프로그래밍에 대해 궁금합니다. 믹스 인 / 모듈은 항상 나를 혼란스럽게합니다.
- include : 지정된 모듈 메소드 에서 대상 클래스의 인스턴스 메소드 로 혼합
- extend : 지정된 모듈 메소드 에서 대상 클래스의 클래스 메소드 로 혼합
가장 큰 차이점은 이것입니까 아니면 더 큰 용은 숨어 있습니까?
예 :
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!"
답변
당신이 말한 것이 맞습니다. 그러나 그것보다 더 많은 것이 있습니다.
클래스 Klazz
와 모듈 이 있다면를 Mod
포함하여 의 메소드 에 대한 액세스 인스턴스를 제공합니다 . 또는 당신은 확장 할 수 있습니다 로 바치는 클래스 에 대한 액세스 의 방법을. 또한로 임의의 객체를 확장 할 수 있습니다 . 이 경우 같은 클래스를 가진 다른 모든 객체 는 그렇지 않더라도 개별 객체는 의 메소드를 얻습니다 .Mod
Klazz
Klazz
Mod
Klazz
Mod
Klazz
Mod
o.extend Mod
Mod
o
답변
extend- 지정된 모듈의 메소드와 상수를 대상의 메타 클래스 (예 : 싱글 톤 클래스)에 추가합니다.
- 를 호출
Klazz.extend(Mod)
하면 Klazz는 Mod의 메소드를 클래스 메소드로 갖습니다. - 를 호출
obj.extend(Mod)
하면 obj에는 Mod의 메소드가 (인스턴스 메소드로) 있지만 다른 인스턴스obj.class
에는 해당 메소드가 추가 되지 않았습니다 . extend
공개 방법입니다
포함 – 기본적으로 대상 모듈 / 클래스의 인스턴스 메소드로 지정된 모듈의 방법으로 혼합합니다. 예 :
- 를 호출
class Klazz; include Mod; end;
하면 이제 모든 Klazz 인스턴스가 Mod의 메소드에 액세스 할 수 있습니다 (인스턴스 메소드). include
컨테이너 클래스 / 모듈 내에서 호출되기 때문에 전용 메소드입니다.
그러나 모듈은 종종 메소드를 원숭이 패치하여 동작을 무시 include
합니다 included
. 이것은 레거시 Rails 코드에서 매우 두드러집니다. Yehuda Katz에서 세부 사항 더 .
include
다음 코드를 실행했다고 가정하고 기본 동작과 함께 에 대한 자세한 내용
class Klazz
include Mod
end
- Mod가 Klazz 또는 그 조상 중 하나에 이미 포함되어 있으면 include 문이 적용되지 않습니다
- 충돌하지 않는 한 Klazz의 Mod 상수도 포함합니다.
- Klazz가 Mod의 모듈 변수에 액세스 할 수 있도록합니다 (예 :
@@foo
또는@@bar
- 주기적 포함이 있으면 ArgumentError 발생
- 모듈을 호출자의 직계 조상으로 연결합니다 (예 : Klazz.ancestors에 Mod를 추가하지만 Klazz.superclass.superclass.superclass의 체인에 Mod가 추가되지 않으므로
super
Klazz # foo를 호출 하면 확인하기 전에 Mod # foo를 확인합니다. Klazz의 실제 수퍼 클래스의 foo 메소드에 대한 자세한 내용은 RubySpec을 참조하십시오.)
물론 루비 코어 문서 는 항상 이런 일을하기에 가장 좋은 장소입니다. RubySpec 프로젝트 는 기능을 정확하게 문서화했기 때문에 환상적인 리소스였습니다.
답변
맞습니다.
배후에 include는 실제로 append_features 의 별명입니다. (문서에서) :
Ruby의 기본 구현은이 모듈이 aModule 또는 해당 조상 중 하나에 아직 추가되지 않은 경우이 모듈의 상수, 메소드 및 모듈 변수를 aModule에 추가하는 것입니다.
답변
때 include
클래스로 모듈은 모듈의 방법으로 가져 인스턴스 메소드 .
그러나 extend
모듈을 클래스에 넣으면 모듈 메서드를 클래스 methods 로 가져옵니다 .
예를 들어 Module_test
다음과 같이 정의 된 모듈이있는 경우 :
module Module_test
def func
puts "M - in module"
end
end
이제 include
모듈입니다. 클래스 A
를 다음과 같이 정의하면 :
class A
include Module_test
end
a = A.new
a.func
출력은 다음과 같습니다 M - in module
..
줄 include Module_test
을 바꾸고 extend Module_test
코드를 다시 실행하면 다음과 같은 오류가 발생 undefined method 'func' for #<A:instance_num> (NoMethodError)
합니다.
로 메소드 호출 a.func
을 A.func
변경하면 출력이 다음으로 변경됩니다 M - in module
.
위의 코드 실행에서 우리 include
는 모듈 일 때 메소드가 인스턴스 메소드가 되고 extend
, 모듈 일 때 그 메소드가 클래스 메소드 가 된다는 것이 분명합니다 .
답변
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
사용 사례는 다음과 같습니다.
ClassThatIncludes 클래스에 ReusableModule 모듈 을 포함 하면 메소드, 상수, 클래스, 서브 모듈 및 기타 선언이 참조됩니다.
ReusableModule 모듈을 사용하여 ClassThatExtends 클래스 를 확장 하면 메소드와 상수가 복사 됩니다. 분명히주의하지 않으면 동적으로 정의를 복제하여 많은 메모리를 낭비 할 수 있습니다.
ActiveSupport :: Concern을 사용하는 경우 .included () 기능을 사용하면 포함 클래스를 직접 다시 작성할 수 있습니다. 우려 내의 모듈 ClassMethods 는 포함 클래스로 확장 (복사)됩니다.
답변
또한 작동하는 메커니즘을 설명하고 싶습니다. 내가 옳지 않으면 정정하십시오.
사용할 때 include
클래스에서 일부 메소드를 포함하는 모듈에 링크를 추가합니다.
class A
include MyMOd
end
a = A.new
a.some_method
객체에는 메소드가 없으며 클래스와 모듈 만 있습니다. 따라서 메시지를 a
받으면 고유 클래스 에서 some_method
검색 방법 some_method
을 a
시작한 다음 A
클래스에서 A
클래스 모듈 에 링크하여 검색 합니다.
우리가 사용할 때 extend
객체의 고유 클래스의 모듈에 연결을 추가합니다. 따라서 A.new.extend (MyMod)를 사용하면 A의 인스턴스 고유 클래스 또는 a'
클래스에 모듈에 대한 연결을 추가 합니다. 그리고 A.extend (MyMod)를 사용하면 A (object ‘s, classes are objects) eigenclass에 연결을 추가합니다 A'
.
따라서 메소드 검색 경로 a
는 다음과 같습니다. a => a ‘=> a’class => A에 연결된 모듈.
또한 조회 경로를 변경하는 prepend 메소드가 있습니다.
a => a ‘=> 앞에 붙인 모듈 => A => 포함 된 모듈 A
내 하찮은 영어 실력에 죄송하다는 말씀을 드리고 싶습니다.