【问题标题】:Why Property must be initialized when there is auto back-end field generated为什么生成自动后端字段时必须初始化属性
【发布时间】:2018-07-12 09:07:23
【问题描述】:

我是属性新手,从 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.
}

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

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

然后我继续下一步以进一步了解它,因此我添加了自定义 getter。

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){

    }

}

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

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

【问题讨论】:

  • 你应该试试数据类,它和java bean类一样。所以你不需要创建 getter、setter 和所有。
  • @VijayMakwana 我不是在问解决方案,只是在问原因。

标签: kotlin


【解决方案1】:

是的,这不会编译:

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,这就是编译器感觉良好的原因。

为了让您免于困惑,互联网上有很多关于 Kotlin 的解释,您可能会发现熟悉这种相对较新的语言非常困难,但请记住,一切都需要您进行测试。
我在网页中找到了以下代码:

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

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

如果不是,它会显示为可编译

【讨论】:

  • This is where you explicitly admit that whatever happens I will never set a value to data 为什么我必须承认?那么var的需要是什么?我认为编译器方面有问题,或者有一个我不知道的深层次的东西。
  • var 的需求显而易见:变量。如果属性是只读的,则它不是变量。只有当您通过声明一个空的 setter 来承认这不是一个变量时,编译器才会接受 var(尽管它没有用)。
  • 它有记录吗?还是你在描述你的经历?
  • 文档在这里:Properties and Fields,但它并没有扩展到适合我们所有的问题,所以练习、猜测和更多练习是我的解决方案。
【解决方案2】:

你有点回答了你自己的问题。当您同时覆盖 getter 和 setter 并且不访问 field 时,没有支持字段。

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

如果你的 getter 依赖于另一个稍后才初始化的字段,这会导致很多关于默认值应该是什么的混淆。

考虑这段代码,假设 provider 的值没有定义:

var data: String
    get() = provider.data

什么是默认值?你想要一个空吗?空字符串?也许整个对象初始化应该崩溃?为此需要显式的默认值声明。

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

【讨论】:

  • 抱歉迟到了。我对此进行了更多探索,但又遇到了一个问题,为什么 val data: String get() = provider.data 可以正常工作?
【解决方案3】:
class Employee{
    var data: String
    get() = "default value"
}

var 表示同时存在 getter 和 setter。因为您没有编写 setter,所以您获得了默认的 setter,它访问支持字段。所以有一个backing field,它需要被初始化。

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

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

我没有看到更改规则有任何明显问题,以便仅在 getter 中访问字段时才需要初始化字段,并且可能会在只有一个访问者使用 field 时添加警告.但我可能会遗漏一些东西,并且也没有看到这样做有什么好处。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-05-31
    • 1970-01-01
    • 1970-01-01
    • 2012-04-07
    • 2012-01-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多