Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/kotlin/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Kotlin 我如何从调用的内部“返回”到“使用”?_Kotlin - Fatal编程技术网

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

在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
    }
}
这在我的实际代码中尤其尴尬,因为我有一个嵌套循环,所以我需要使用带标签的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
是正确的选择,因为它永远不会发生。