Kotlin 我如何从调用的内部“返回”到“使用”?
在Kotlin中,此代码编译:Kotlin 我如何从调用的内部“返回”到“使用”?,kotlin,Kotlin,在Kotlin中,此代码编译: private fun bar(): Boolean = TODO() fun works(): Int { while (true) { if (bar()) { return 5 } } } (这是我真实代码的简化示例,用于说明我遇到的问题。) 我实际上需要在循环过程中使用一个文件,并在退出时关闭: fun openFile(): InputStream = TODO() fun d
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
}
}
这在我的实际代码中尤其尴尬,因为我有一个嵌套循环,所以我需要使用带标签的break
解决此问题的另一种方法是为循环指定一个命名函数:
fun workaround_with_named_function(): Int {
fun loop(input: InputStream): Int {
while (true) {
if (bar()) {
return 5
}
}
}
return openFile().use { loop(it) }
}
这似乎好一点,但我仍然感到惊讶的是
use
抽象太容易泄漏,以至于我无法从循环中提前返回。有没有一种方法可以使用use
并在循环中提前返回,这样就不那么麻烦了?因为Kotlin编译器不够聪明,无法理解use
和内部代码一起使用会从函数返回一些东西。这种行为的原因是无法保证编译器只调用lambda一次
另一种解决方法是在函数末尾引发异常:
fun doesnt_work(): Int {
openFile().use { input ->
while (true) {
if (bar()) {
return 5
}
}
}
throw IllegalStateException("Something goes wrong")
}
p.S.我不确定,但它似乎可以在没有任何黑客攻击的情况下编译,何时将添加到Kotlin。它很可能会出现在1.3版中,这应该是可行的
fun openFile(): InputStream = TODO()
fun doesnt_work(): Int {
return openFile().use { input ->
while (true) {
if (bar()) {
return@use 5
}
}
-1 // unreachable return value
// just to help Kotlin infer the return type
}
}
请记住,use
是一个返回值与lambda的返回值完全相同的函数。因此,在lambda中返回值(这里是5
)并返回use
的返回值应该可以工作
fun openFile(): InputStream = TODO()
fun doesnt_work(): Int {
return openFile().use { input ->
while (true) {
if (bar()) {
return@use 5
}
}
-1 // unreachable return value
// just to help Kotlin infer the return type
}
}
另外,如果我是你,我会这样写函数:
fun doesnt_work() = openFile().use { input ->
while (true) if (bar()) return@use 5
-1
}
在第一个doesnt_work()示例中,如果在use块之后返回一个伪值,即使它永远不会返回,编译器也会很高兴。我建议在上一次会议上提出这个问题,以便从事语言/库工作的人员能够看到它或提供更好的答案。请看一下我的答案,我认为它比你的解决方法和其他答案都好。这对我不起作用。我得到
类型推断失败。预期类型不匹配:推断类型为除use
上预期的Int以外的任何类型,并且类型不匹配:推断类型为Unit,但上预期的Int
,而上预期的Int
。我正在使用kotlinc jvm 1.2.31。添加一个不可访问的最终返回语句将起作用,请参阅我的更新。很抱歉没有测试code@LaurenceGonsalves嗨,你能看一下我的编辑吗?我认为,AssertionError
是正确的选择,因为它永远不会发生。