我对属性不熟悉,并从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
,因此没有后端字段。而且效果很好。
那么最后一个问题应该是何时初始化属性?什么时候生成后端字段?
答案 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 }}。但是我可能会丢失一些东西,也看不出这样做有什么好处。