【问题标题】:Return type mismatch when throwing exception in finally在finally中抛出异常时返回类型不匹配
【发布时间】:2018-08-30 14:21:24
【问题描述】:

我使用的是 Kotlin 1.2.60。

val someString: String = try {

    String.format("Okay %s", "there") // or any function that returns String

} catch(exception: Exception) {

    try {
        // fun incrementErrorCount() { ... }
        incrementErrorCount() // [1] Error: Type mismatch: Inferred type is Unit but String was expected
    } finally {
        throw exception
    }

    // throw exception // [2] Fixes the type mismatch when uncommented, but raises Warning: Unreachable code
}

我在 1 收到 类型不匹配 错误,因为它期望 incrementErrorCount() 返回一个字符串 - 但返回类型应该无关紧要,因为它总是会重新抛出 @ 987654324@反正。

我添加了2,它修复了类型不匹配 错误,但引发了无法访问代码 警告,因为函数永远不会超出throw 中的finally .

我做错了什么?我怎样才能让它编译没有错误或警告?

【问题讨论】:

  • 如果你有什么方法抛出异常,为什么要使用finally 块?直接在 try 块之后编写 throw 异常,这将使其成为 catch 块的最后一条语句。

标签: kotlin


【解决方案1】:

查看Kotlin Referencetry-catch-finally,您会看到:

try-表达式的返回值要么是try 块中的最后一个表达式,要么是catch 块(或多个块)中的最后一个表达式。 finally 块的内容不影响表达式的结果。

所以这意味着虽然你的意图是正确的,并且没有办法从你的第二个 try 块返回,但 Kotlin 编译器仍然会将 Unit 作为它的返回值,并且由于规范而不修改它finally 块。

要让编译器知道catch 块将始终返回Nothing,您需要throw 移出finally

【讨论】:

  • 该参考链接肯定描述了1 上的类型不匹配 错误。我很惊讶尽管如此,如果我在2 投掷,它仍然会给我一个无法访问的代码 警告。如果我在incrementErrorCount() 之后添加throw ce,它也会给我同样的警告。就像它认识到 finally { throw } 块意味着没有返回值,但不会将逻辑应用于调用的返回值。
  • @mrb 是的,finally 块总是被执行,并且由于它总是抛出,下面的代码是无法访问的。但是,编译器插入的返回类型仍然是Unit 而不是Nothing,这会给您错误
【解决方案2】:

try-catch 是 Kotlin 中的表达式。如果try 块成功运行而没有抛出任何东西,则返回它的最后一个值。如果抛出异常,则返回 catch 块的最后一个值。

在你的情况下,如果String.format 没有抛出异常,它的结果是从第一个try-catch 返回的,你很好。这是简单的路线。

如果String.format 抛出异常,则返回catch 块的最后一个表达式,即嵌套try-finally 本身的第二个表达式。这可以通过两种方式结束:

  • 如果嵌套的try 块成功运行,它的最后一个表达式(在本例中为incrementErrorCount)就是它的求值结果,然后该调用的结果将分配给someString。这是您遇到的类型错误,看起来 incrementErrorCount 没有返回要分配的 String
  • 如果嵌套的try 失败,则抛出异常,完全取消someString 的分配。

添加第 [2] 行修复了您的错误,因为嵌套的 try-catch 没有用作分配给 someString 的值,它刚刚运行,throw 表达式取消了 someString 的整个分配。

【讨论】:

  • 错了。 finally 总是被执行,不管try 块是否抛出异常
【解决方案3】:

我假设你想要的逻辑是,如果 String.format 失败,你会让异常被抛出,但也会增加你的错误计数。在那种情况下,我认为您需要(未经测试)...

val someString: String = try {

    String.format("Okay %s", "there") // or any function that returns String

} catch(exception: Exception) {

    try {
        // fun incrementErrorCount() { ... }
        incrementErrorCount()
    } 
    catch (dontCare: Exception) {
    }

    throw exception 

}

【讨论】:

  • 问题是我做错了什么?,你没有给出任何解释为什么问题中的代码不起作用
  • 我认为你混淆了你的捕获块。如果我正确理解了您的意图,那么内部块就可以吞下来自 incrementErrorCount() 的异常。所以就让它这样做吧。外部块可以重新抛出属于它的异常。
  • 我会以同样的方式解释问题中的代码(仍然有人可能想要记录incrementErrorCount() 中发生的错误,但这是另一个主题)。还是你不解释为什么问题的代码编译失败
  • "finally 块的内容不影响表达式的结果。" kotlinlang.org/docs/reference/exceptions.html
猜你喜欢
  • 1970-01-01
  • 2010-11-09
  • 1970-01-01
  • 2010-10-03
  • 1970-01-01
  • 2012-03-13
  • 2017-07-11
  • 2014-05-23
相关资源
最近更新 更多