2012-12-27 2 views
3
내가 about_message_passing.rb 루비 화두 일하고 다음과 같이 코드가 method_missing을 위해 일하고있어

:루비 화두 "보내기"메시지 전달에 대한 블록 인수

def method_missing(method_name, *args, &block) 
    @messages << method_name 
    @object.__send__(method_name, *args, &block) 
end 

이 코드가 작동하는 것 같다,하지만 난하지 않습니다 * args에 필요한 스 플랫 (splat)이 필요하고 블록에 &이 필요한 이유를 이해하십시오.

메서드를 정의하는 경우 * 및 &은 배열 인수와 블록 인수를 나타내는 데 사용되지만 해당 메서드를 send 메서드와 함께 사용하여 개체의 메서드를 호출 할 때 ?

답변

9

한 번에 하나씩 살펴 보겠습니다. method_missing을 완전히 가져와야합니다. 혼란 스러울 정도로 진행되기 때문입니다. 실제로는 완전히 관련이 없습니다.


스 플랫 *은 2 가지를 수행합니다. 정의의 인수 인에서는 여러 인수를 배열에 흡수합니다. 메서드 호출에서 사용되는 경우 배열을 개별 인수로 분리합니다. 둘 다 사용하면 다른 수의 인수에 전달할 수 있습니다.

def foo(*args) 
    bar(*args) 
end 

def bar(a, b, c) 
    puts a 
    puts b 
    puts c 
end 

foo(1,2,3) # prints 1, 2 and then 3 

기본적으로 모든 인수를 전달하므로 동일한 패턴입니다.


&은 block 인수입니다. 메서드 호출 당 정확히 하나가있을 수 있습니다. 끝에서 멈추는 블록입니다. 그것은 논쟁을 직접적으로 진행하지 않는다는 점에서 특별한 논증입니다. 메서드 정의에서 마지막 인수로 &someblock을 캡처하여 변수에 블록을 캡처 할 수 있습니다.

그런 다음 동일한 구문을 사용하여 호출에서 블록을 전달할 수 있습니다.

이렇게하면 걸지 블록을 호출하지 않고 다른 방법으로 전달할 수 있습니다. 일반적으로 통과 된 블록을 실행하려면 보통 yield을 사용해야하기 때문에 항상 필요한 것은 아닙니다. 그러나 당신이 그것을 실행하는 것 이외의 것을하고 싶다면 블록 자체에 대한 참조를 포착해야합니다.


이렇게 두 가지를 결합하면 궁극적 인 방법 전달자가됩니다. 모든 인수와 모든 블록을 끝까지 캡처하여 다른 메소드로 보냅니다.

# forwards everything to the method `bar` 
def foo(*args, &block) 
    bar(*args, &block) 
end 

마지막으로, send는 방법입니다. 메소드의 이름 다음에 인수 (배열이 아님)가 올 것으로 예상되며 교수형 블록을 선택적으로 처리 할 수 ​​있습니다. 즉

: 플랫 그냥 방법 매개 변수 정의/인수 목록에 적용되지 않습니다

foo.send methodName, *args, &block 
+0

참고. 또한 블록 매개 변수 정의/인수 목록, * 및 * 할당에도 적용됩니다. –

0

제 생각에는 블록을 직접 전달할 때마다 & block_name 구문을 사용합니다.

또한 Object#send의 메서드 서명에는 배열이 아닌 끝이없는 인수가 사용됩니다. 따라서 splatted 값 * args를 전달하면 쉼표로 구분 된 args를 전달한 것과 같습니다.

1

메소드 정의의 splat은 "일치하지 않는 모든 인수를 가져 와서 배열에 넣습니다"를 의미합니다 (루비 1.8에서는 항상 마지막 인수 였지만 중간에 1.9 개의 표시가 있음). 메소드 호출에서 사용

역방향 : 그것은 블록을 포착하고로를 전환하는 방법의 정의 : 그것은이 배열을 가지고

foo(a,b) #call foo with 2 arguments: a and b 
foo([a,b]) #call foo with a single array argument 
foo(*[a,b]) # call foo with 2 arguments: a and b 

&는 유사한 인자로 그 내용을 사용하여 의미 proc하지만 메서드 호출에서 해당 메서드에 대한 블록에 proc (또는 객체와 같은 proc 객체 - 응답하는 모든 것)가 해당 블록의 블록으로 바뀝니다.

method_missing에 대해 일반적으로 원래의 메소드 호출의 모든 인수와 블록을 따라 가십시오.