为什么“返回”在 Kotlin 中可以返回“返回”?

2022-09-03 12:12:17

这个问题可能听起来很愚蠢,但其中没有拼写错误。

fun test(): Any {
    return return true
}

这在 Kotlin 中实际上是可能的。尽管编译器警告

无法访问的代码

用于外部返回。但这只是一个警告。

我不想将Java与Kotlin进行比较,但我对Java是否同样适用于Java很感兴趣。

public class Test {
  // ...
  static int test() {
    return return 1;
  }
}

事实并非如此!

/Test.java:8: 错误: 表达式
的非法开始返回返回 1;
^
/Test.java:8: error: not a statement
return return 1;
^
2 错误

为什么 Kotlin 是这样设计的?


答案 1

return是 Kotlin 中的一个表达式,其返回类型为 ,该类型充当所有其他类型的子类型。例如,这使您能够以类型安全的方式执行此操作,而无需额外的检查行:Nothingnull

fun getInt(): Int? = ...

fun printInt() {
    val int: Int = getInt() ?: return
    println(int)
}

的类型可以在这里,因为这是猫王算子两端最接近的常见超类型,这要归功于 它是 的子类型。getInt() ?: returnIntNothingInt

同样的事情也适用于 ,您也可以将其与运算符一起使用,以指示您希望取消对值的执行,而不必担心以后的类型。throwElvisnull

这导致了一个奇怪的怪癖,比如

fun x(): Int {
    return return throw return throw throw return 0
}

是有效的语法,因为该类型使每个表达式从右到左有效读取。实际发生的事情是,这将执行,并且将永远不会到达其余的代码,正如编译器警告的那样。Nothingreturn 0


答案 2

因为该语句是返回 的表达式。因此,以下内容也会进行编译:returnNothing

fun main(args: Array<String>) {
    val r = return
}

它在文档中说明:

Kotlin 有三个结构跳跃表达式:

  • return.默认情况下,从最近的封闭函数或匿名函数返回。[...]

所有这些表达式都可以用作较大表达式的一部分:

val s = person.name ?: return

这些表达式的类型是类型。Nothing

由于是任何其他类型的子类型,因此它具有使奇怪的陈述(如您的问题中的陈述)有效的能力,尽管它们似乎非常错误......Nothing

实际上,在KotlinConf上有一个有趣的演讲,看看下面有趣的事情:

fun getText(): String {
  val s = return throw return "Hello"
}

println(getText())
//prints "Hello"