无法在 Kotlin 的 when 语句内初始化变量。

huangapple go评论50阅读模式
英文:

Can't initialize variables inside of when statement in Kotlin

问题

由于某种原因,我的Kotlin程序不会初始化在when语句内赋值的变量。以下是代码:

import kotlin.random.Random
import kotlin.random.nextInt

val mood: String

when(Random.nextInt(1..2)) {
    1 -> {
        mood = "loud"
        println("$mood")
    }
    2 -> {
        mood = "quiet"
        println("$mood")
    }
}

println("$mood")

在when语句内的行会被打印,但当我运行最后一行时,我会收到一个“变量'mood'必须被初始化”错误。

我不知道我可能在这里做错了什么...

英文:

For whatever reason, my Kotlin program won't initialize variables assigned inside a when statement. Here's the code:

import kotlin.random.Random
import kotlin.random.nextInt

val mood: String

when(Random.nextInt(1..2)) {
    1 -> {
        mood = "loud"
        println("$mood")
    }
    2 -> {
        mood = "quiet"
        println("$mood")
    }
}

println("$mood")

The lines inside the when statement are printed, but when I run the last line, I get a "Variable 'mood' must be initialized" error.

I don't know what I could possibly be doing wrong here...

答案1

得分: 3

这是一个编译错误,而不是执行错误。

从编译器的角度来看,您的 when 语句不是穷尽的,因为一个 Int 可能不仅仅是 1 或 2。实际上,nextInt(1..2) 只返回这些数字的事实并没有被编译器考虑在内,编译器只关注类型。

要解决这个问题,您应该添加一个 else 语句,在其中也初始化 mood,例如:

val mood: String

when (Random.nextInt(1..2)) {
    1 -> {
        mood = "loud"
        println(mood)
    }

    2 -> {
        mood = "quiet"
        println(mood)
    }
    else -> {
        mood = "currently impossible"
    }
}

println(mood)

或者,您可以使用常规的 varlateinit var 代替 val

要么直接初始化一个常规变量:

var mood: String = ""

要么使用 lateinit var

lateinit var mood: String

在后一种情况下,编译器无法再确保初始化(这实际上是为什么在您的代码中首次出现警告的原因)。

此外,如果您希望在初始化后强制 mood 为只读,这两种方法可能都不太合适。

英文:

This is a compilation error, not an execution one.

Your when statement is not exhaustive from the compiler point of view because an Int can be more than just 1 or 2. The fact that, in practice, nextInt(1..2) only returns those numbers is not taken into account by the compiler, which is looking at the type.

To solve the issue you should add an else statement where you also initialize mood, e.g.:

val mood: String

when (Random.nextInt(1..2)) {
    1 -> {
        mood = "loud"
        println(mood)
    }

    2 -> {
        mood = "quiet"
        println(mood)
    }
    else -> {
        mood = "currently impossible"
    }
}

println(mood)

Alternatively you can use a regular var or lateinit var instead of a val.

Either you initialize a regular var directly:

var mood: String = ""

Or use a lateinit var:

lateinit var mood: String

In the latter case, the compiler can't ensure initialization anymore (which is actually why it's complaining in the first place in you code).

Also, both of these might be not desiderable if you want to enforce mood to be read-only after initialization.

答案2

得分: 0

在Kotlin中,使用关键字val声明的变量必须在声明点或类的构造函数中进行初始化。在你的代码中,mood变量没有被赋予初始值,而你试图在when语句内部为它赋值。然而,编译器无法确定在运行时是否会执行任何一个分支,因此它不会将变量视为完全初始化。

要解决这个问题,你可以将mood变量声明为var而不是val,或者在声明时为它赋予初始值。以下是使用var修复此问题的代码版本:

import kotlin.random.Random
import kotlin.random.nextInt

var mood: String

when (Random.nextInt(1..2)) {
    1 -> {
        mood = "loud"
        println("$mood")
    }
    2 -> {
        mood = "quiet"
        println("$mood")
    }
}

println("$mood")

通过使用var而不是val,你表明这个变量可以在以后重新赋值。由于mood变量在when语句的两个分支中都被赋值,编译器不再抱怨它未初始化。

请注意,when分支的顺序应该覆盖所有可能的情况,否则你可能会遇到“when表达式必须是穷尽的”警告。在你的情况下,nextInt的范围是1到2,因此这两个分支应该足够了。

英文:

In Kotlin, variables declared with the val keyword must be initialized at the point of declaration or in the constructor of the class. In your code, the mood variable is declared without an initial value, and you are trying to assign values to it inside the when statement. However, the compiler is unable to determine if either of the branches will be executed at runtime, so it doesn't consider the variable as fully initialized.

To fix this issue, you can either declare the mood variable as a var instead of a val or assign an initial value to it when declaring it. Here's an updated version of your code using a var:
import kotlin.random.Random
import kotlin.random.nextInt

var mood: String

when (Random.nextInt(1..2)) {
    1 -> {
        mood = "loud"
        println("$mood")
    }
    2 -> {
        mood = "quiet"
        println("$mood")
    }
}

println("$mood")

By using a var instead of a val, you indicate that the variable can be reassigned later. Since the mood variable is assigned within both branches of the when statement, the compiler no longer complains about it being uninitialized.

Note that the order of the when branches should cover all possible cases, otherwise you might encounter a "when expression must be exhaustive" warning. In your case, the range of nextInt is 1 to 2, so the two branches should be sufficient.

huangapple
  • 本文由 发表于 2023年6月2日 00:47:31
  • 转载请务必保留本文链接:https://go.coder-hub.com/76384080.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定