Grant Birchmeier
Grant Birchmeier

Reputation: 18484

How can I break out of a Kotlin `repeat` loop?

How do I break out of a Kotlin repeat loop?
(I see plenty of answers about forEach, but I want to see a repeat-specific answer.)

These don't work (they are functionally identical):

    repeat(5) { idx ->
        println(">> $idx")
        if(idx >= 2)
            return@repeat   // use implicit label
    }

    repeat(5) @foo{ idx ->
        println(">> $idx")
        if(idx >= 2)
            return@foo      // use explicit label
    }

In both those cases, you get:

>> 0
>> 1
>> 2
>> 3
>> 4

(The return@ in both those blocks actually acts like a continue, which you can see yourself if you add a println after the if-block.)

So how can I break out of a repeat?

Upvotes: 14

Views: 9379

Answers (2)

Adam Millerchip
Adam Millerchip

Reputation: 23091

That seems like quite an abuse of the repeat function. My understanding is that if you write repeat, you intend it to repeat for that number of times. Any fewer is surprising.

For your example, I would use a for loop:

for (idx in 0 until 20) {
    println(">> $idx")
    if (idx >= 2)
        break
}

I think using the right tool is better than trying to coerce the wrong one (repeat) to do what you want.


repeat itself is implemented as a for loop:

for (index in 0 until times) {
    action(index)
}

Trying to use it for anything more than that and you may as well write your own version, rather than wrap up extra behaviour on top of it.

Upvotes: 10

Grant Birchmeier
Grant Birchmeier

Reputation: 18484

It turns out that repeat (as well as forEach) are not actually loops. They're higher-order functions, that is, they are functions that take functions as parameters.

(I find this frustrating: They look and act like loops, and feature prominently in the Kotlin docs. Why not just go all the way and promote them to proper loops in the language?)

To break out of a repeat loop, this is the best answer I can devise:

    run repeatBlock@ { // need to make a label outside of the repeat!
        repeat(20) { idx ->
            println(">> $idx")
            if(idx >= 2)
                return@repeatBlock
        }
    }

This is the result of that:

>> 0
>> 1
>> 2

I wish I could do it without introducing a new indent-level, but I don't think it's possible.

Upvotes: 14

Related Questions