'return' doesn't jump out of forEach i

2019-05-11 23:05发布

问题:

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

回答1:

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



回答2:

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
        }
    }
}


回答3:

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.