在Kotlin中,此代码编译:
private fun bar(): Boolean = TODO()
fun works(): Int {
while (true) {
if (bar()) {
return 5
}
}
}
(这是我真实代码的一个简化示例,用于说明我遇到的问题 . )
我实际上需要在这个循环中使用一个文件,并在退出时关闭:
fun openFile(): InputStream = TODO()
fun doesnt_work(): Int {
openFile().use { input ->
while (true) {
if (bar()) {
return 5
}
}
}
} // line 42
这不编译 . 我收到错误:
错误:(42,5)Kotlin:具有块体('')的函数中需要的'return'表达式
我找到了两种方法来解决这个问题,但两者都有点尴尬 .
一种方法是使用变量来保存结果,并在设置时从循环中断:
fun works_but_awkward(): Int {
openFile().use { input ->
val result: Int
while (true) {
if (bar()) {
result = 5
break
}
}
return result
}
}
这在我的真实代码中尤其笨拙,因为我有一个嵌套循环,因此我需要使用带标签的中断 .
解决此问题的另一种方法是为循环创建一个命名函数:
fun workaround_with_named_function(): Int {
fun loop(input: InputStream): Int {
while (true) {
if (bar()) {
return 5
}
}
}
return openFile().use { loop(it) }
}
这看起来好一点,但我仍然感到惊讶的是 use
抽象是如此漏洞,以至于我无法在循环中提前返回 . 有没有办法使用 use
与循环中的早期返回不那么尴尬?
2 回答
原因Kotlin编译器不够智能,不能理解
use
里面的代码会从函数返回一些东西 . 这种行为的原因是无法保证编译器只能调用一次lambda .另一种解决方法是在函数末尾抛出异常:
P.S. 我不确定,但似乎可以在没有任何黑客的情况下编译contract system将被添加到Kotlin . 它可能会在版本1.3中
这应该工作 .
请记住,
use
是一个函数,其返回值与lambda的返回值完全相同 . 所以在lambda中返回值(这里是5
)并返回use
的返回值应该有效 .另外,如果我是你,我会写这样的函数: