Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/tfs/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Kotlin 我应该在声明、init块、构造函数或lateinit上初始化变量吗?_Kotlin - Fatal编程技术网

Kotlin 我应该在声明、init块、构造函数或lateinit上初始化变量吗?

Kotlin 我应该在声明、init块、构造函数或lateinit上初始化变量吗?,kotlin,Kotlin,我想知道kotlin中初始化变量的4种方法(我知道)和哪一种方法最受欢迎有什么区别 首先,在声明时初始化它: class MyClass { var textString: String = "Hello world" } 其次,在init块上初始化它: class MyClass { var textString: String init { textString = "Hello world" } } 第三,使

我想知道kotlin中初始化变量的4种方法(我知道)和哪一种方法最受欢迎有什么区别

首先,在声明时初始化它:

class MyClass {
   var textString: String = "Hello world"
}
其次,在init块上初始化它:

class MyClass {
   var textString: String

   init {
      textString = "Hello world"
   }
}
第三,使用构造函数:

class MyClass {
    var textString : String

    constructor() {
        this.textString = "Hello world"
    }
}
class Foo(var bar: String = "default value")
第四,lateinit:

class MyClass {
    lateinit var textString : String

    fun initializeVariable() { //Assume this is called by something
        this.textString = "Hello world"
    }
}

我主要是寻找编译时间和总体“良好实践”的差异。我知道您可以使用一些“技巧”,比如使用init块初始化一些变量,这些变量总是相同的,不管使用的构造函数是什么,但这是合适的方法吗?

lateinit
不相关,因为它不初始化任何东西

同一行上的初始化仅适用于简单属性。您可以使用闭包,然后调用它们,就像这样
vali={//complex code}()
,但这很难看


有关构造函数vs
init
块的详细讨论,请参阅。理解初始化顺序的最简单方法是创建一个包含主、次和
init
块的类,然后使用
println
或简单地使用调试器跟踪执行。

从技术角度看,没有太大区别,至少就简单属性而言,如示例中所示,该属性无论如何都会初始化

lateinit
修饰符在这里是一个小小的例外-它允许延迟初始化:就像说“我现在不能设置有意义的值,但我确信它将在第一次使用之前设置”。它在Kotlin-Spring框架集成中很有用,因为某些原因不想/不能使用构造函数注入,并且允许属性注入

 @Autowired lateinit var foo: Foo
或者在使用Spring的
@值时

 @Value("\#{props.foo}") lateinit var foo: String
不过,从读者/维护者的角度来看,这是有区别的,当您需要一些额外的功能时,比如说前提条件验证。根据经验,尽早初始化属性:首选方法是在主构造函数中:

class MyClass {
    var textString : String

    constructor() {
        this.textString = "Hello world"
    }
}
class Foo(var bar: String = "default value")
你的代码的读者,也许是未来的你,不必通过代码来理解“默认值”从何而来——它就在构造函数中

此外,客户机代码可以在构造对象时轻松更改值,或者保留默认值

// set new value
val foo: Foo = Foo(bar = "specific value other than default")

// leave the default
val defaultFoo: Foo = Foo()
在类主体中初始化属性,强制客户机代码首先使用默认值创建实例,然后才重写

val foo = Foo()
foo.bar = "not so default"
此外,如果您想检查一些先决条件,那么在主构造函数中设置值时更容易检查。例如,foo字符串属性不能为空:

class Foo(var bar: String = "default") {
    init {
        require(bar.isNotBlank()) { "Bar cannot be blank" }
   }
}
在可能的情况下,我会使用构造函数初始化


另外,如果你愿意花几美元买一本关于Kotlin良好实践和模式的书,我强烈推荐Marin Moskała的有效Kotlin

有多种方法,因为有多种需求,因此没有适合所有人的方法,所以我投票以基于意见的方式结束这个问题。“我想知道初始化变量的4种方法之间有什么区别”我不认为这是基于观点的。最理想的解决方案是什么“我同意这听起来是基于观点的,但这是因为我的措辞不当。我的意思是我想在哪里使用每一个,以及为什么这一个会比其他的好。如果你把一个字段设置为一个已知的常数,最好的方法就是选择1。如果需要使用构造函数参数,请使用constructor/init。当您说
lateinit
在Kotlin的早期很有用,你是在暗示它不再有用了吗?@Tenfour04它对于属性注入或在构造过程中无法初始化某些东西时仍然有用-例如在android中,你等待平台调用
onCreate
,因为这是你可以引用应用程序资源的第一个点。@Pawel这就是我的意思。我已经澄清了答案,正如@Pawel提到的,当通过属性而不是构造函数使用依赖注入时,这仍然很有用。