首页 > 解决方案 > 满足提供的条件时如何从传递给递归函数的 lambda 中断

问题描述

我正在编写一个自定义loopdsl,我希望它的用法如下所示


    var counter1 = 0
    var counter2 = 0
    loop {
            counter1 += 1
            println(counter1)
            stopIf(counter1 == 5) // loop should terminate here and not execute rest of the code if condition matches

            counter2 += 2
            println(counter2)
            stopIf(counter2 == 8) // loop should terminate here and not execute rest of the code if condition matches

        }

我有以下代码,它允许我stopIf在主体中的任何地方编写任意次数,loop但是当条件匹配时,它不会立即终止,而是执行循环体的其余部分,然后终止。


    @UseExperimental(ExperimentalTime::class)
    open class Loop {
        var stop = false

        val loopInterval = 1.seconds

        suspend fun loop(block: suspend () -> Unit): Unit = loop(loopInterval, block)

        suspend fun loop(minimumInterval: Duration, block: suspend () -> Unit): Unit =
            loopWithoutDelay { delayedResult(maxOf(minimumInterval, loopInterval), block) }

        private suspend fun loopWithoutDelay(block: suspend () -> Unit) {
            block()
            if (stop) return else loopWithoutDelay(block)
        }

        suspend fun <T> delayedResult(minDelay: Duration, f: suspend () -> T): T = coroutineScope {
            val futureValue = async { f() }
            delay(minDelay.toJavaDuration())
            futureValue.await()
        }

        fun stopIf(condition: Boolean) {
            if (condition) {
                stop = condition // once stop condition matches, then do not override it with following false condtions
            }
        }
    }

    @ExperimentalTime
    suspend fun loop(block: suspend Loop.() -> Unit) =
        Loop().run { loop { block(this) } }

我曾尝试使用returnwithlabel但它不起作用。有什么办法可以做到这一点?

标签: kotlinkotlin-coroutinesgradle-kotlin-dsl

解决方案


例如,可以通过抛出轻量级异常来完成。您必须声明自定义异常:

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

并抓住它loopWithoutDelay

private suspend fun loopWithoutDelay(block: suspend () -> Unit) {
    try {
        while (true) {
            block()
        }
    } catch (e: LoopStopException) {
        //do nothing
    }
}


推荐阅读