I have this Kotlin code, why return@forEach doesn't jump out of forEach? It continues the loop until it finishes, removing reversed() doesn't solve problem:
rendered_words.reversed().forEach { rw ->
if (rw.y - the_top > 0 && rw.y - the_top < height) {
new_top = rw.y
return@forEach
}
}
smoothScrollTo(Math.min(text_y - height, new_top))
I tried replacing return@forEach with break@forEach but Kotlin compiler says :
Error:(785, 25) The label '@forEach' does not denote a loop
How about this approach?
rendered_words.reversed().firstOrNull { rw -> rw.y - the_top > 0 && rw.y - the_top < height }
?.let { new_top = it }
if(new_top != null) {
smoothScrollTo(Math.min(text_y - height, new_top))
}
because what you seem to try to get here is the first item that matches your condition, and the first/firstOrNull is better there than the forEach
If you want to jump out of forEach, you should use a run block :
run breaker@ {
rendered_words.reversed().forEach { rw ->
if (rw.y - the_top > 0 && rw.y - the_top < height) {
new_top = rw.y
return@breaker
}
}
}
My answer to this is using Kotlin's amazing extension mechanism which means you can add methods wherever you like:
/**
* Iterate a list.
* The consumer can break the iteration by returning
* Control.BREAK
* Returns <tt>true</tt> if no break occured
*
*/
enum class Control { BREAK, CONTINUE }
fun <T> List<T>.each(consumer : (T) -> Control) : Boolean {
for( t in this) {
when(consumer(t)) {
Control.BREAK -> return false
}
}
return true
}
Now you can just do:
list.each {
if(...) {
logger.debug { "break" }
return@each Control.BREAK
} else {
logger.debug { "continue" }
return@each Control.CONTINUE
}
}
I think extension methods are a very compelling feature in Kotlin that you'll have to deal with sooner or later anyways so you might as well use it to make your code more readable.