在函数中声明 val 而不进行初始化

问题描述 投票:0回答:2
class Solution { 
    val message: String  //error : val must be initialized or abstract
    message = "love" //error : val cannot be reassigned
}

我明白这里发生了什么 - val 无法重新分配。
所以当我需要 val 但无法初始化它时我曾经使用

by lazy

class Solution {
    fun love(){
        val message : String
        message = "love"   //this works
        message = "hate"   //this is error "val cannot be reassigned"
    }
}

这里我可以不用初始化就delcare val,然后再写代码

message = "love"
。这里发生了什么?

kotlin syntax initialization
2个回答
2
投票

@deHaar正确地注意到,只有

var
(可变变量)适合您的情况。

您得到的错误绝对正确且符合预期。

这里发生了什么事?

当您声明一个只读变量而不对其进行初始化时,您必须确保每个执行路径在此只读变量中都有一个值。这意味着 Kotlin 会确保您的只读变量在每个使用它的地方是否都已初始化,如果该变量使用不当,则会引发错误。

这里只有一个执行路径,因为没有

when
if
语句可以将执行分成多个可能的路径。

class Solution {
    fun love(){
        val message : String
        message = "love"   // Kotlin knows that `message` was not yet initialized
        message = "hate"   // Kotlin knows that `message` was yet initialized! It does not allow to modify the value.
    }
}

这是 Kotlin 文档的内容:

...也可以(但不鼓励)拆分声明和初始赋值,甚至根据某些条件在多个位置进行初始化。您只能在编译器可以证明每个可能的执行路径都已初始化该变量的点处读取该变量。如果您以这种方式创建只读变量,您还必须确保每个可能的执行路径都只分配给它一次。

执行路径示例

使用

when
if
语句创建两个或多个执行路径。 执行路径可以以图表的形式呈现,我将使用#number作为节点号。示例:

class Solution {
    fun love(){
        // #1
        val message : String
        if (System.currentTimeMillisec() % 2 == 0) {
            message = "Not empty"      
            // #2
        }

        if (message.isEmpty) { // Error! Message could be not initialized at this point! 
            println("Empty message")
            // #3
        }
    }
}

看这个例子,不能编译,我们可以计算出至少3条执行路径。

  1. #1(没有输入任何 if 语句。所有条件都是
    false
  2. #1 -> #2
  3. #1 -> #3

Kotlin 可以计算这些路径并检查

message
变量是否在每个使用的路径中都被初始化。正如我们所看到的,一旦您到达第二个
if
语句的评估(在第一条和第三条路径的情况下),您的程序就会崩溃,因为
message
没有值。它在内存中没有地址,运行该程序的计算机不知道如何从不存在的地址获取值。

现在,让我们修改此代码以使其正常工作:

class Solution {
    fun love(){
        // #1
        val message : String
        if (System.currentTimeMillisec() % 2 == 0) {
            message = "Not empty"      
            // #2
        } else {
            message = ""
            // #3
        }

        if (message.isEmpty) { // Error! Message could be not initialized at this point! 
            println("Empty message")
            // #4
        }
    }
}

执行路径:

  1. #1 -> #2
  2. #1 -> #3 -> #4

在此示例中,Kotlin 确定

message
只读变量已初始化,因为节点 2 或节点 3 之一有 100% 的机会将被执行。在
message
获取其初始值(初始化)的行之后,Kotlin 将此变量视为具有值的只读变量。

欢迎提问。我会尽力简化这个答案。


0
投票

嗨,我知道我回答已经晚了,但其他人给出的所有答案都没有回答问题。

那么真正的问题是什么?问题在于 kotlin 允许您声明一个没有初始值的

val
变量,但您必须像下面的代码中那样显式声明数据类型:

class Solution {
    fun love(){
        val message : String
        message = "love"   //this works
    }
}

真正的问题是为什么下面的代码即使在 kotlin 中允许这样的初始化也不起作用?

class Solution { 
    val message: String 
    message = "love" //error
}

答案很简单,您正在类块内执行重新分配语句。请注意,您只能在类块中执行选定的有效语句。要解决此问题,您需要在代码块中进行初始化,如下所示:

class Solution {
    val message: String

    init {
        message = "love" // works
    }
}

为了验证我所说的是否正确,请将 val 更改为 var 并将重新分配语句放入类块中,您将收到语法错误

class Solution {
    var message: String
    message = "sdfsdf" // error syntax
}
``
© www.soinside.com 2019 - 2024. All rights reserved.