Kotlin의`forEach`에서`break` 및`continue`


120

코 틀린처럼, 아주 좋은 반복하는 기능을 가지고 forEachrepeat,하지만 난 할 수 없습니다입니다 breakcontinue운영자가 그들과 함께 작업 (로컬 및 비 로컬) :

repeat(5) {
    break
}

(1..5).forEach {
    continue@forEach
}

목표는 기능적 구문을 최대한 가깝게 사용하여 일반적인 루프를 모방하는 것입니다. 일부 이전 버전의 Kotlin에서는 확실히 가능했지만 구문을 재현하는 데 어려움을 겪고 있습니다.

문제는 레이블 (M12)이있는 버그 일 수 있지만 첫 번째 예제는 어쨌든 작동 할 것이라고 생각합니다.

특별한 트릭 / 주석에 대해 어딘가에서 읽은 것 같지만 주제에 대한 참조를 찾을 수 없습니다. 다음과 같이 보일 수 있습니다.

public inline fun repeat(times: Int, @loop body: (Int) -> Unit) {
    for (index in 0..times - 1) {
        body(index)
    }
}

1
현재 Kotlin에서는 실제로이를 모방 할 수 있습니다 ( continue@labelbreak@label기능 을 기다리는 동안 ), 관련 질문 참조 : stackoverflow.com/questions/34642868/…
Jayson Minard

1
이 질문에 당신 만의 실존에 대해 물어 여부에 대해 명확한 설명을 사용할 수 breakcontinue기능 루프, 또는 당신이 똑같은 일을 다른 답을 찾고 있다면. 후자를 거부했기 때문에 전자가 해당되는 것으로 보입니다.
Jayson Minard

그들이 그 1.3 코 틀린 추가 보인다
티그 Babajanyan

트윗 담아 가기 링크가 있습니까?
voddan

@voddan, 아니, 난 그냥 작동 시도하지
티그 Babajanyan

답변:


69

편집 :
Kotlin의 문서 에 따르면 주석을 사용하는 것이 가능합니다.

fun foo() {
    listOf(1, 2, 3, 4, 5).forEach lit@{
        if (it == 3) return@lit // local return to the caller of the lambda, i.e. the forEach loop
        print(it)
    }
    print(" done with explicit label")
}

원래 답변 :
을 제공하기 때문에 (Int) -> Unit컴파일러가 루프에서 사용되는 것을 알지 못하기 때문에 끊을 수 없습니다.

몇 가지 옵션이 있습니다.

일반 for 루프를 사용하십시오.

for (index in 0 until times) {
    // your code here
}

루프가 메서드의 마지막 코드 인 경우 메서드에서 나가는 데
사용할 수 있습니다 return(또는 메서드 return value가 아닌 경우 unit).

방법 사용 계속하기 위해
반환되는 사용자 지정 반복 방법 방법을 만듭니다 Boolean.

public inline fun repeatUntil(times: Int, body: (Int) -> Boolean) {
    for (index in 0 until times) {
        if (!body(index)) break
    }
}

사실, 내 질문은 반복이 아니라 특정 구문을 작동시키는 것에 관한 것이 었습니다. Kotlin 이정표에서 가능했다는 것을 기억하지 못하십니까?
voddan 2015-09-13

1
기억이 안나요. 하지만 아마도 휴식과 계속을 많이 사용하지 않기 때문일 것입니다. 이 문제를 참조하십시오. "Estimation-No estimation"이라고되어 ​​있습니다.
Yoav Sternberg 2015 년

1
break그리고 continue단지 루프에서 작동합니다. forEach, repeat그리고 다른 모든 메서드는 루프가 아닌 메서드입니다. 아브 몇 가지 대안을 제시하지만, breakcontinue단지 방법에 대한 작업으로, 표준되지 않습니다.
Kirill Rakhman 2015 년

@YoavSternberg 훌륭합니다! 이 오래된 문서의 평화는 내가 찾고 있던 것입니다! 따라서 기능은 아직 구현되지 않았으며 향후 버전을 위해 남겨졌습니다. 별도의 답을 만들 관심이 있다면, 나는 그것을 표시합니다
voddan

현재 Kotlin에서는 실제로이를 모방 할 수 있습니다 ( continue@labelbreak@label기능 을 기다리는 동안 ), 관련 질문 참조 : stackoverflow.com/questions/34642868/…
Jayson Minard

104

이것은 1에서 5까지 인쇄됩니다. 이 경우 Java return@forEach의 키워드처럼 작동 합니다. continue즉,이 경우에는 여전히 모든 루프를 실행하지만 값이 5보다 크면 다음 반복으로 건너 뜁니다.

fun main(args: Array<String>) {
    val nums = listOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
    nums.forEach {
       if (it > 5) return@forEach
       println(it)
    }
}

1에서 10까지 인쇄되지만 5는 건너 뜁니다.

fun main(args: Array<String>) {
    val nums = listOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
    nums.forEach {
       if (it == 5) return@forEach
       println(it)
    }
}

Kotlin Playground 에서 사용해보세요 .


훌륭하지만, 이것은 여전히 ​​어떤 조건이 충족 될 때 forEach를 너무 일찍 종료 할 수없는 문제를 해결하지 못합니다. 여전히 루프를 계속 실행합니다.
The Fox

1
@TheFox 예, 조건이 충족되면 반환 후 모든 루프와 모든 것을 실행합니다. forEach의 각 작업은 람다 함수이며 현재 forEach 작업에 대한 정확한 중단 작업은 없습니다. 브레이크가 for 루프에서 사용할 수 있습니다, 참조 : kotlinlang.org/docs/reference/returns.html
S-사냥꾼

다음은 a continuebreak예제 가 모두 포함 된 실행 가능한 Kotlin Playground 스 니펫입니다 . pl.kotl.in/_LAvET-wX
ashughes

34

다음을 사용하여 휴식을 취할 수 있습니다.

//Will produce"12 done with nested loop"
//Using "run" and a tag will prevent the loop from running again. Using return@forEach if I>=3 may look simpler, but it will keep running the loop and checking if i>=3 for values >=3 which is a waste of time.
fun foo() {
    run loop@{
        listOf(1, 2, 3, 4, 5).forEach {
            if (it == 3) return@loop // non-local return from the lambda passed to run
            print(it)
        }
    }
    print(" done with nested loop")
}

그리고 다음을 통해 계속할 수 있습니다.

//Will produce: "1245 done with implicit label"
fun foo() {
    listOf(1, 2, 3, 4, 5).forEach {
        if (it == 3) return@forEach // local return to the caller of the lambda, i.e. the forEach loop
        print(it)
    }
    print(" done with implicit label")
}

여기 누구든지 추천하는 것처럼 ... 문서를 읽으십시오 : P https://kotlinlang.org/docs/reference/returns.html#return-at-labels


좋은 솔루션입니다. 아주 잘 작동합니다. 사용하지 않아도 @loop같은 결과 를 얻을 수있는 것 같지만 .
Paras Sidhu

실제로 명시 적 태그 "@loop"를 생략하고 암시 적 태그 "@run"을 사용할 수 있습니다. 여기서 핵심적인 측면은 람다 호출자에 대한 로컬 반환입니다. 나중에 루프를 로컬로 반환 할 수 있도록 일부 범위 내에서 루프를 래핑해야합니다.
Raymond Arteaga


17

Kotlin 문서에 나와 있듯이 사용하는 return것이 좋습니다. kotlin의 좋은 점은 중첩 된 함수가있는 경우 레이블을 사용하여 반환의 출처를 명시 적으로 작성할 수 있다는 것입니다.

기능 범위 반환

fun foo() {
  listOf(1, 2, 3, 4, 5).forEach {
    if (it == 3) return // non-local return directly to the caller of foo()
    print(it)
  }
  println("this point is unreachable")
}

로컬 리턴 (forEach = 계속 진행을 중단하지 않음)

fun foo() {
  listOf(1, 2, 3, 4, 5).forEach lit@{
    if (it == 3) return@lit // local return to the caller of the lambda, i.e. the forEach loop
    print(it)
  }
  print(" done with explicit label")
}

문서를 확인하세요. 정말 좋습니다. :)


3
경고 : return @ lit은 멈추지 않습니다forEach
Jemshit Iskenderov

맞아요. 의도 된 것입니다. 첫 번째 해결책이지만 루프 내부에 지침이있는 경우 돌아가거나 이동할 위치를 선택할 수 있습니다. 두 번째 경우에 return을 사용하면 중지됩니다 ;-)
cesards

Return @ lit 좋아하는 계속 전화하기
pqtuan86

10

continue 유형 행동 forEach

list.forEach { item -> // here forEach give you data item and you can use it 
    if () {
        // your code
        return@forEach // Same as continue
    }

    // your code
}

break당신이 사용해야 하는 유형 행동의 경우 for in until또는 for in목록에 따라 Nullable또는Non-Nullable

  1. 대한 Null 허용 목록 :

    for (index in 0 until list.size) {
        val item = list[index] // you can use data item now
        if () {
            // your code
            break
        }
    
        // your code
    }
  2. 들어 비 Null 허용의 목록 :

    for (item in list) { // data item will available right away
        if () {
            // your code
            break
        }
    
        // your code
    }

2

중첩 루프 forEach ()에 대한 Break 문 :

listOf("a", "b", "c").forEach find@{ i ->
    listOf("b", "d").forEach { j ->
        if (i == j) return@find
        println("i = $i, j = $j")
    }
}

결과:

i = a, j = b
i = a, j = d
i = c, j = b
i = c, j = d

익명 함수가있는 Continue 문 :

listOf(1, 2, 3, 4, 5).forEach(fun(value: Int) {
    if (value == 3) return
    print("$value ")
})

결과:

1 2 4 5 

0

에 대한 변경 가능

for(it in myList){
   if(condition){
     doSomething()
   }else{
     break //or continue
    }
} 

해시 맵에서 작동합니다.

 for(it in myMap){
     val k = it.key
     val v = it.value

       if(condition){
         doSomething()
       }else{
         break //or continue
        }
    }
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.