Kotlin中能否调用lambda内部函数实现非局部返回退出lambda
解决方案
核心实现思路是利用Kotlin inline函数支持非局部返回 + Nothing类型函数中断执行的特性,可以完全替代异常实现匹配失败时的立即中断,无额外性能开销,也不会执行后续无效逻辑。
具体实现代码
matches 扩展函数实现
inline fun List<Char>.matches(build: PatternScope.() -> Unit): Boolean { val iterator = this.iterator() var matchSuccess = true // 失败回调,返回Nothing,调用后直接中断整个lambda执行 val onFail: () -> Nothing = { matchSuccess = false return@matches false } val scope = PatternScope(iterator, onFail) scope.build() // 只有全部匹配通过才会走到这里,检查是否有剩余未匹配字符 return matchSuccess && !iterator.hasNext() }
PatternScope 类实现
class PatternScope( private val iterator: Iterator<Char>, private val onFail: () -> Nothing ) { inline fun one(predicate: (element: Char) -> Boolean) { if (!iterator.hasNext() || !predicate(iterator.next())) { onFail() } } inline fun moreThan(n: Int, predicate: (element: Char) -> Boolean) { var count = 0 while (iterator.hasNext() && predicate(iterator.next())) { count++ } if (count <= n) { onFail() } } // 占有型量词不需要回溯,嵌套作用域实现非常简单 inline fun lessThan(n: Int, build: PatternScope.() -> Unit) { var count = 0 while (iterator.hasNext() && count < n) { build() count++ } if (count >= n) { onFail() } } }
原理解释
onFail的返回类型为Nothing,Kotlin编译器会认定该函数永远不会正常返回,调用onFail()之后的所有代码都会被标记为不可达,不会执行。- 由于
matches是inline函数,onFail中的return@matches属于合法的非局部返回,会直接跳出整个matches函数返回false,buildlambda中后续的所有匹配方法调用都不会触发。 - 完全不需要抛出异常,避免了异常栈展开的性能开销,也不需要在每个方法中加冗余的
matchFailed状态判断,DSL的写法和你原来的实现完全一致,不需要修改上层代码。
通用场景实现
对于你提到的任意lambda内部函数直接中断lambda执行的需求,都可以用同样的方案实现:
// 定义lambda的作用域类 class LambdaScope(private val exitLambda: () -> Nothing) { fun someMethod() { val needExit = true // 替换为实际的条件判断 if (needExit) { exitLambda() } // 正常逻辑 } fun someOtherMethod() { // 其他逻辑 } } // 封装lambda的执行入口 inline fun runCustomLambda(block: LambdaScope.() -> Unit) { val exit: () -> Nothing = { return@runCustomLambda } val scope = LambdaScope(exit) scope.block() } // 使用方式 fun main() { runCustomLambda { someMethod() // 符合条件时直接退出整个lambda someOtherMethod() // 不会被执行 } }
内容的提问来源于stack exchange,提问作者mateu
相关产品推荐
相关产品推荐

