그루비 폐쇄에서 "계속"을 시뮬레이션하기위한 최상의 패턴

StackOverflow https://stackoverflow.com/questions/205660

  •  03-07-2019
  •  | 
  •  

문제

그루비는 지원하지 않는 것 같습니다 break 그리고 continue 폐쇄 내에서. 이것을 시뮬레이션하는 가장 좋은 방법은 무엇입니까?

revs.eachLine { line -> 
    if (line ==~ /-{28}/) {
         // continue to next line...
    }
}
도움이 되었습니까?

해결책

당신은 깨끗하지 않고 깨끗하게 계속 지원할 수 있습니다. 특히 각 라인과 같은 것들이 있습니다. 브레이크를 지원할 수 없다는 것은 이러한 방법을 평가하는 방식과 관련이 있으며, 방법에 전달 될 수있는 루프를 완료하지 않기위한 고려 사항은 없습니다. 계속 지원하는 방법은 다음과 같습니다.

최상의 접근 방식 (결과 값이 필요하지 않다고 가정).

revs.eachLine { line -> 
    if (line ==~ /-{28}/) {
        return // returns from the closure
    }
}

샘플이 실제로 간단하다면, 이것은 가독성에 좋습니다.

revs.eachLine { line -> 
    if (!(line ==~ /-{28}/)) {
        // do what you would normally do
    }
}

또 다른 옵션은 계속해서 Bytecode 레벨에서 계속 진행되는 일을 시뮬레이션합니다.

revs.eachLine { line -> 
    while (true) {
        if (line ==~ /-{28}/) {
            break
        }
        // rest of normal code
        break
    }

}

휴식을 지원하는 가능한 한 가지 방법은 예외를 통해입니다.

try {
    revs.eachLine { line -> 
        if (line ==~ /-{28}/) {
            throw new Exception("Break")
        }
    }
} catch (Exception e) { } // just drop the exception

다른 실제 예외를 마스킹하지 않기 위해 사용자 정의 예외 유형을 사용하려면, 특히 숫자 formatexceptions 또는 ioexceptions와 같은 실제 예외를 던질 수있는 다른 처리가 진행중인 경우 특히 그렇습니다.

다른 팁

폐쇄는 루프/반복 구조물이 아니기 때문에 파손되거나 계속 될 수 없습니다. 대신 반복 논리를 처리/해석/처리하는 데 사용되는 도구입니다. 다음과 같이 처리하지 않고 폐쇄에서 단순히 반환하여 주어진 반복을 무시할 수 있습니다.

revs.eachLine { line -> 
    if (line ==~ /-{28}/) {
            return
    }

}

휴식 지원은 폐쇄 수준에서 발생하지 않고 대신 폐쇄를 수락 한 방법 호출의 의미에 의해 암시됩니다. 요컨대, 그것은 특정 조건이 충족 될 때까지 처리 할 수있는 전체 컬렉션을 처리 해야하는 컬렉션과 같은 컬렉션에서 "각각"을 호출하는 대신 의미합니다. 대부분의 (모든?) 시간은 당신이 실제로하고 싶은 일을 폐쇄에서 깨뜨려야 할 필요성을 느낍니다. 반복 중에 특정 조건을 찾는 것입니다. 슬프게도 API 중 일부는 찾기 메소드에 대한 지원이 부족합니다 ... 파일. 언어가 포함되어 있어야한다고 주장하는 데 소비 된 모든 시간은 브레이크/계속이 포함되어 있어야합니다. FirstDirmatching (Closure C) 또는 FindLineMatching (Closure C)과 같은 것이 먼 길을 가고 "내가 왜 나가지 못하는가 ...?"의 99+%에 대답 할 것입니다. 메일 링리스트에 나타나는 질문. 즉, 메타 클래스 또는 카테고리를 통해 이러한 방법을 직접 추가하는 것은 사소한 일입니다.

class FileSupport {
   public static String findLineMatching(File f, Closure c) {
      f.withInputStream {
         def r = new BufferedReader(new InputStreamReader(it))
         for(def l = r.readLine(); null!=l; l = r.readLine())
             if(c.call(l)) return l
         return null
      }
   }
}

using(FileSupport) { new File("/home/me/some.txt").findLineMatching { line ==~ /-{28}/ }

예외 및 기타 마술과 관련된 다른 해킹은 효과가있을 수 있지만 어떤 상황에서는 여분의 오버 헤드를 소개하고 다른 상황에서는 가독성을 복잡하게 만듭니다. 진정한 대답은 코드를보고 대신 반복하거나 검색하는지 묻는 것입니다.

Java에서 정적 예외 객체를 사전 제작 한 다음 내부 폐쇄에서 (정적) 예외를 던지면 런타임 비용이 최소화됩니다. 실제 비용은 예외를 제작하지 않고 예외를 만들 때 발생합니다. Martin Odersky (Scala의 발명가)에 따르면, 많은 JVMS는 실제로 단일 점프에 대한 던지기 지침을 최적화 할 수 있습니다.

이것은 휴식을 시뮬레이션하는 데 사용할 수 있습니다.

final static BREAK = new Exception();
//...
try {
  ... { throw BREAK; }
} catch (Exception ex) { /* ignored */ }

사용 반품 에게 계속하다 그리고 어느 폐쇄 부서지다.

예시

파일 내용 :

1
2
----------------------------
3
4
5

그루비 코드 :

new FileReader('myfile.txt').any { line ->
    if (line =~ /-+/)
        return // continue

    println line

    if (line == "3")
        true // break
}

산출:

1
2
3

이 경우, 당신은 아마도 find() 방법. 폐쇄가 처음으로 통과 된 후에는 멈 춥니 다.

와 함께 RX-Java 반복 할 수있는 것을 관찰 가능한 사람으로 변환 할 수 있습니다.

그런 다음 교체 할 수 있습니다 계속하다 a 필터 그리고 부서지다 ~와 함께 ... 할 때

예는 다음과 같습니다.

import rx.Observable

Observable.from(1..100000000000000000)
          .filter { it % 2 != 1} 
          .takeWhile { it<10 } 
          .forEach {println it}
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top