为什么在生成自动后端字段时必须初始化属性

时间:2018-07-12 09:07:23

标签: kotlin

我对属性不熟悉,并从Java移到了kotlin。我在属性上苦苦挣扎,我对它了解很多。但是初始化属性会让我感到困惑,什么时候应该初始化它,或者什么时候不需要初始化就可以工作。

让我借助代码进行解释。以下是在生成后端字段时需要初始化属性的代码,在发布代码之前,让我先发布kotlin official website中的段落。

  

如果属性使用   至少一个访问器的默认实现,或者   自定义访问器通过字段标识符引用它。

现在这是下面的代码。

class Employee{
    var data: String // because there are default implementation of get set
                    // so there will be a back-end field.
}
  

所以我必须初始化它,否则编译错误。

好,我可以理解它,因为有人可以访问它,因此不会有任何值会产生错误的结果。

然后我接下来要进一步了解它,因此我添加了自定义吸气剂。

class Employee{
    var data: String
    get() = "default value"
}

这也会生成后端字段,因此初始化时会发生编译错误。我可以理解,因为没有初始化值,所以编译器会抱怨它。

可能是编译器不够聪明 yet 来检查是否有值可以通过自定义getter获得此属性的结果,所以不要抱怨初始化只是返回必要时使用该值。

但是如果有人访问它,那么默认值已经存在,那应该没有问题,那为什么编译器仍然会抱怨呢?

然后我也要进一步实施自定义设置器。

class Employee{

    var data: String
    get() = "default value"
    set(value){
        field = value
    }

}

仍然有一个后端字段,因为我们已经访问了field,因此编译器生成了后端字段。 相同的错误,应初始化。

然后是最后一个可以正常工作的阶段,如下所示。

class Employee{

    var data: String
    get() = "default value"
    set(value){

    }

}

现在,我无法访问自定义field getter中的setter,因此没有后端字段。而且效果很好。

那么最后一个问题应该是何时初始化属性?什么时候生成后端字段?

3 个答案:

答案 0 :(得分:2)

是的,这不能编译:

class Employee{
    var data: String
    get() = "default value"
}

但是这样做:

class Employee{
    val data: String
    get() = "default value"
}

所以也许编译器通过声明属性必须初始化来进行错误的声明,希望您承认data是您无法更改的。我说也许。
现在可以编译的部分:

class Employee{

    var data: String
    get() = "default value"
    set(value){

    }
}

这是您明确承认无论发生什么事情我都永远不会将值设置为data的地方,这就是为什么编译器感觉良好的原因。

只是让您免于更多的混乱,Internet上有很多关于Kotlin的解释,您可能会发现很难熟悉这种相对较新的语言,但是请记住,所有内容都需要您进行测试。
我在网页中找到以下代码:

class User{
    var firstName : String
        get() = field
        set(value) {field = value}

    var lastName : String
        get() = field
        set(value) {field = value}
}

,如果不是,则显示为可编译

答案 1 :(得分:1)

您回答了自己的问题。当您同时覆盖getter和setter且不访问field时,没有备用字段。

关于您的“编译器不够聪明”:get()函数在运行时实际上是RAN,因此编写很多编译器代码只是为了评估返回值是否为静态,并且应该默认注入它实在太小众了。用例。

如果您的getter依赖于稍后才初始化的另一个字段,这将导致对于默认值应该是什么造成很大的困惑。

假设未定义provider的值,请考虑以下代码:

var data: String
    get() = provider.data

什么是默认值?您要空吗?空字符串?也许整个对象初始化都应该崩溃?为此,需要明确的默认值声明。

这就是lateinit var的概念:如果您确定在执行任何set之前将get值,则可以使用此关键字来防止编译器错误并设置默认值值。

答案 2 :(得分:0)

class Employee{
    var data: String
    get() = "default value"
}

var意味着同时有一个getter和setter。因为您没有编写设置器,所以将获得默认设置器,该设置器将访问后备字段。因此,有一个备用字段,需要对其进行初始化。

  

但是如果有人访问它,那么默认值已经存在,那应该没有问题,那为什么编译器仍然会抱怨呢?

因为这使规则更简单:必须初始化所有带有后备字段的属性。反过来这可能是因为在Java中不必初始化字段,而这是已知的bug来源。我想说这还可以避免可能的错误,因为大概您实际上并不希望setter的结果永远不可访问,但是初始化不能解决该问题。

我看不到任何更改规则的明显问题,以便仅在使用getter进行访问时才需要初始化字段,并且可能只有一个访问者使用{{1 }}。但是我可能会丢失一些东西,也看不出这样做有什么好处。