loops - when - return function kotlin
¿Cómo hago un "descanso" o "continuar" cuando estoy en un ciclo funcional dentro de Kotlin? (4)
En Kotlin, no puedo hacer un break
o continue
dentro de un bucle de función y mi lambda, como puedo hacerlo desde un ciclo for
normal. Por ejemplo, esto no funciona:
(1..5).forEach {
continue@forEach // not allowed, nor break@forEach
}
Hay documentación antigua que menciona que esto está disponible, pero parece que nunca se implementó. ¿Cuál es la mejor manera de obtener el mismo comportamiento cuando quiero continue
o break
desde el lambda?
Nota: esta pregunta fue escrita y respondida intencionalmente por el autor ( Preguntas de respuesta automática ), de modo que las respuestas idiomáticas a los temas de Kotlin comúnmente formulados están presentes en SO. También para aclarar algunas respuestas realmente antiguas escritas para alfas de Kotlin que no son precisas para Kotlin actual.
Puede usar return de la expresión lambda que imita un continue
o break
dependiendo de su uso.
Aquí hay un ejemplo que imita continue
:
(1..5).forEach {
if (it == 3) return@forEach // mimic continue@forEach
// ... do something more
}
Y puede ir más complicado y usar etiquetas cuando tiene situaciones de anidamiento o confusas:
(1..3).forEach outer@ { x ->
(1..3).forEach inner@ { y ->
if (x == 2 && y == 2) return@outer // mimic continue@outer
if (x == 1 && y == 1) return@inner // mimic continue@inner
// ... do something more
}
}
Si quiere hacer un break
, necesita algo fuera del ciclo del que pueda regresar, aquí utilizaremos la función run()
para ayudarnos:
run breaker@ {
(1..20).forEach { x ->
if (x == 5) return@breaker // mimic break@forEach
// ... do something more
}
}
En lugar de run()
, podría ser let()
o apply()
o cualquier cosa que tenga naturalmente rodeando el para forEach
lugar que quiera romper. Pero también se saltará el código dentro del mismo bloque que sigue a forEach
así que tenga cuidado.
Estas son funciones en línea así que realmente no agregan sobrecarga.
Lea los documentos de referencia de Kotlin para Devoluciones y Saltos para todos los casos especiales, incluso para funciones anónimas.
Aquí hay una prueba unitaria que prueba que todo esto funciona:
@Test fun testSo32540947() {
val results = arrayListOf<Pair<Int,Int>>()
(1..3).forEach outer@ { x ->
(1..3).forEach inner@ { y ->
if (x == 2 && y == 2) return@outer // continue @outer
if (x == 1 && y == 1) return@inner // continue @inner
results.add(Pair(x,y))
}
}
assertEquals(listOf(Pair(1,2), Pair(1,3), Pair(2,1), Pair(3,1), Pair(3,2), Pair(3,3)), results)
val results2 = arrayListOf<Int>()
run breaker@ {
(1..20).forEach { x ->
if (x == 5) return@breaker
results2.add(x)
}
}
assertEquals(listOf(1,2,3,4), results2)
}
Si hay una necesidad de usar continue
o break
, no es ideal para usar para cada forEach
comparar con el for-loop
normal
Si realmente desea encadenar su comando, y actuar como un bucle for, use la cadena funcional normal, en lugar de forLoop
Ej. Para
for(i in 0 until 100 step 3) {
if (i == 6) continue
if (i == 60) break
println(i)
}
Utilice el map
como for-loop, filterNot
como continue y asSequence() & first
para break
(0 until 100 step 3).asSequence()
.filterNot { it == 6 }
.map { println(it); it }
.first { it == 60 }