首页 > 解决方案 > 我应该在声明、初始化块、构造函数还是后期初始化时初始化变量?

问题描述

我想知道在 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 MyClass {
    lateinit var textString : String

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

我主要是在寻找编译时间和整体“良好实践”的差异。我知道您可以使用一些“技巧”,例如使用 init 块来初始化一些始终相同的变量,而不管使用的构造函数如何,但这是否是适当的做法?

标签: kotlin

解决方案


从技术的角度来看,没有太大区别,至少在示例中的简单属性方面 - 属性无论如何都会被初始化。

修饰符在lateinit这里有一点例外——它允许延迟初始化:就像说“我现在无法设置有意义的值,但我确信它会在第一次使用之前设置”。它在 Kotlin - Spring Framework 集成中很有用,当一个由于某种原因不想/不能使用构造函数注入时,它允许属性注入。

 @Autowired lateinit var foo: Foo

或者在使用 Spring 的@Value注解时

 @Value("\#{props.foo}") lateinit var foo: String

但是,从读者/维护者的角度来看,这是有区别的,当您需要一些额外的功能时,比如前置条件验证。根据经验,尽早初始化您的属性:首选方法是在主构造函数中:

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 String 属性不能为空:

class Foo(var bar: String = "default") {
    init {
        require(bar.isNotBlank()) { "Bar cannot be blank" }
   }
}

在可能的情况下,我会使用构造函数初始化。

另外,如果你愿意花几美元买一本关于 Kotlin 良好实践和模式的书,我强烈推荐 Marin Moskała 的Effective Kotlin https://leanpub.com/effectivekotlin


推荐阅读