how to break from lambda passed to recursive function when provided condition met

后端 未结 2 1281
时光取名叫无心
时光取名叫无心 2021-01-28 11:50

I am writing a custom loop dsl and I want it\'s usage to look like below


    var counter1 = 0
    var counter2 = 0
    loop {
            counter1          


        
相关标签:
2条回答
  • 2021-01-28 12:34

    I didn't understand much about the function delayedResult, because none of the dsl's public functions return a result. However, I come up with an solution for cancelling the loop.

    As far as I understood, we have to have a loop that doesn't block the current thread. Therefore, it must be run in a coroutine, but in order to be able to cancel the loop, the dsl must run its own coroutine. This inner coroutine is run using coroutineScope, so it suspends the parent coroutine until it's finished or cancelled.

    @ExperimentalTime
    class Loop {
        private val loopInterval = 1.seconds
    
        suspend fun loop(block: suspend () -> Unit) = loop(loopInterval, block)
    
        suspend fun loop(minimumInterval: Duration, block: suspend () -> Unit):Job  = coroutineScope {
            launch {
                while (true) {
                    block()
                    delay(minOf(minimumInterval, loopInterval).toLongMilliseconds())
                }
            }
        }
    
        suspend fun stopIf(condition: Boolean) = coroutineScope {
            suspendCancellableCoroutine<Unit> {
                if (condition) it.cancel() else it.resumeWith(Result.success(Unit))
            }
        }
    }
    
    @ExperimentalTime
    suspend fun loop(block: suspend Loop.() -> Unit):Job {
        return Loop().run {
            this.loop {
                block(this)
            }
        }
    }
    
    0 讨论(0)
  • 2021-01-28 12:38

    It can be done for example with throwing a lightweight exception. You have to declare custom exception:

    class LoopStopException : Throwable("Stop look", null, false, false) // lightweight throwable without the stack trace
    

    and catch it in loopWithoutDelay:

    private suspend fun loopWithoutDelay(block: suspend () -> Unit) {
        try {
            while (true) {
                block()
            }
        } catch (e: LoopStopException) {
            //do nothing
        }
    }
    
    
    0 讨论(0)
提交回复
热议问题