2011-09-25 3 views
3

#value : message의 반환 값은 블록에 전송 될 때 해당 블록의 마지막 문장의 값입니다. 그래서 [ 1 + 2. 3 + 4. ] value은 7로 평가됩니다. 가끔은 사용하기가 어렵습니다. 명시 적으로 반환 값을 설정하고 블록 실행을 중지하는 방법이 있습니까?smalltalk 블록 - 명시 적으로 반환 값을 설정하고 블록 실행을 중단 할 수 있습니까?

운동을하려면 가상 #return : 메시지를 사용하지 않고이 블록을 다시 쓰고 얼마나 추한 지보십시오. 나는 뭔가를 놓치고 있어야합니다.

[ :one :two | 
    one isNil ifTrue: [ two isNil ifTrue: [ self return: nil ] ifFalse: [ self return: true ] ]. 
    two ifNil: [ self return: false ]. 

(one > two) 
    ifTrue: [ self return: true ] 
    ifFalse: [ (one < two) 
       ifTrue: [ self return: false ] 
       ifFalse: [ self return: nil ] 
      ]. 
] 

편집 : 정말 넌센스이지만, 에서 이해하지 self return: sth 일부 수준 :

답변

7

가드 조항은 어디에도 없습니다 - ^가 아닌 지역이기 때문에 블록 내부 - blah ifTrue: [^ foo]가 반환, 블록 자체가 아닌 블록을 호출하는 메서드에서 돌아옵니다.

큰 블록처럼 큰 블록은 더 작고 이해하기 쉽고 다루기 쉬운 하위 영역으로 리팩토링해야하지만 때로는 항상 가능하지는 않습니다. 이 질문에 대한 답을 말하자면 은 정말 단순하게 할 수 없습니다.

블록이 실제로 복잡하고 더 단순 해지면 (예를 들어, 정보를 너무 많이 분리하면 정보를 너무 많이 표시하지 못할 수 있습니다) 그러면 명시 적 반환 값을 사용할 수 있습니다. 마지막으로

[:one :two | | result marker | 
    result := marker := Object new. 
    (result == marker) ifTrue: ["do one thing, possibly setting result"]. 
    result] 

- 나는 주저 : 당신의 블록이 nil을 반환하지 않는 경우 블록이 nil을 반환 할 경우 특히, 당신이

[:one :two | | result | 
    result := (one isNil and: [two isNil]) ifTrue: [false]. 
    result ifNil: ["do one thing, possibly setting result"]. 
    result] 

같은 것을 할 수있는, 다른 감시 값이 필요합니다 이를 제안하려면 다음을 수행하십시오.

[1 + 2. 
thisContext return: 5. 
3 + 4] value 

5을 반환합니다.

은 ( #ifTrue:ifFalse:는 독자들에게 숙제로 남긴다처럼이 ^ 및 인라인 선택기와 상호 작용하는 방법을 확인.)

2

코드가 하나를 무한 값과 같은 전무 비교 핸들 할 때 시도 할 것2 개.

a := [:one :two | 
    | x y | 
    x := one ifNil: [Float infinity]. 
    y := two ifNil: [Float infinity]. 
    (x = y) ifTrue: [nil] ifFalse: [x > y]] 

#ifTrue 유용한 기능 : ifFalse :, #ifNil : ifNotNil 다음 코드는 상황에 따라 더 읽을 수있는 유사한 테스트 방법들은 블록의 값을 반환 있다는 것을 평가 받는다. 예 : (4 > 1) ifTrue: ['greater'] ifFalse: ['not-greater']'보다 큼'으로 평가됩니다. 이 기능은 종종 꼬리 위치의 중첩 된 블록에서 값을 반환하는 것을 가능하게합니다.

블록 내부의 코드가 너무 복잡해지면 리팩터링을 제안합니다. 그러나 해결 방법에 대한 Frank의 답변을 참조하십시오.

편집 :

으로 위의 코드 번호를 가정 의견에서 지적했다. 나는 또한 다른 유사한 객체와 함께 작동 뭔가를 내놓았다 :

a:= 
[ :one :two | 
    true caseOf: { 
    [one = two]->[nil]. 
    [one isNil]->[true]. 
    [two isNil]->[false] 
    } otherwise: [one>two]] 

#caseOf은 : 구조는 거의 사용되지 않고, 확실히보다 나은 thisContext return:

당신은 계속, 일부 휴식을 구현하고 싶습니다
+0

'value : nil value : nil'을 사용하여 해당 블록을 평가하면'무한대가 아닌'nil을 얻을 수 있습니다. – milan

+0

@milan * one *과 * two *가 0 일 때 내 코드와 너의 코드가 모두 0이됩니다. 당신의 코드에서 :'[: one : two | 하나는 isNil ifTrue : [isNil ifTrue : [self return : nil] ... '내 코드에서 (Infinity = Infinity) 그래서 nil을 반환합니다. –

+1

오, 알았습니다. 당신은 거의 내가 만든 진짜 질문에 대답하지 않고 바로 그것을 가지고 :)하지만 내 코드는 문자열과 아무것도 작동합니다. – milan

1

, 출구입니다 ... 스몰 토크에서 흐름을 제어하는 ​​일반적인 방법은 블록을 사용하는 것입니다. 한 가지 재미있는 해결 방법은 here과 같이 흐름을 중단하는 Block 반환 값이있는 도우미 메서드를 사용하는 것입니다.

Object>>exitThru: aBlock 
    ^aBlock value: [:result | ^result] 

이제 그것을 사용하는 방법을 보자 :

| aBlock | 
aBlock := [ :one :two | 
    self exitThru: [:exit | 
     one isNil ifTrue: [ two isNil ifTrue: [exit value: nil ] ifFalse: [ exit value: true ] ]. 
     two isNil ifTrue: [ exit value: false ]. 
     one > two ifTrue: [ exit value: true ]. 
     one < two ifTrue: [ exit value: false ]. 
     exit value: nil] ]. 

#(('abc' nil) (nil nil) (nil 'def') ('y' 'abc') ('y' 'y') ('y' 'z')) 
    collect: 
     [:pair | 
     aBlock value: pair first value: pair last ] 
-> #(false nil true true nil false) 

편집을 내 첫 번째 버전이었다 불필요하게 복잡하고, 추가로 간접으로 저를 이끌어 기억 할 수 없습니다

| aBlock | 
aBlock := [:wrapOne :wrapTwo | 
    self exitThru: [:exit | 
     [ :one :two | 
     one isNil ifTrue: [ two isNil ifTrue: [exit value: nil ] ifFalse: [ exit value: true ] ]. 
     two isNil ifTrue: [ exit value: false ]. 
     one > two ifTrue: [ exit value: true ]. 
     one < two ifTrue: [ exit value: false ]. 
     exit value: nil ] 
      value: wrapOne value: wrapTwo ] ]. 

글쎄, 유용보다 재밌 네요, 당신이 코드에 더 간단하고 표현 방법을 찾을 수 있기를 바랍니다.

+0

+1 영리한 것들. 사람들은 간결한 예를 보려면 [link] (http://lists.gnu.org/archive/html/help-smalltalk/2008-06/msg00077.html)을 확인해야합니다. –

관련 문제