只有在Kotlin为null时才在Kotlin中实例化变量?

Jac*_*nes 3 java getter nullable backing-field kotlin

可以说,我有一个变量:

var myObject : MyObject? = null

它应该在某个地方清除:

myObject?.clear
myObject = null
Run Code Online (Sandbox Code Playgroud)

并且在使用地点应该绝对不可为空.在Java中,我可以这样做:

private MyObject getMyObject(){
  if(myObject == null) {
    myObject = new MyObject()
  }
  return myObject
}
Run Code Online (Sandbox Code Playgroud)

问题:如何在Kotlin实现这一目标?

我找到了使用elvis-operator的建议:

private fun getMyObject() = myObject ?: MyObject()
Run Code Online (Sandbox Code Playgroud)

但是这并没有MyObjectmyObject变量分配结果(如果要创建新实例).请帮我解决和解释.谢谢你

Ale*_*nov 9

问题是属性的getter和setter不能有不同的类型.我建议一个单独的可空私有属性和一个清除它的方法:

private var _myObject: MyObject? = null

var myObject: MyObject // or val, depending
    get() {
        if (_myObject == null) { _myObject = MyObject() }
        return _myObject!!
    }
    set(value: MyObject) { 
        _myObject?.clear()
        _myObject = value
    }

fun clearMyObject() {
    _myObject?.clear()
    _myObject = null
}
Run Code Online (Sandbox Code Playgroud)

如果您不止一次需要此模式,请编写一个委托.


Sla*_*law 5

您可以使用属性的支持字段.

class Foo {

    var bar: String? = null
        get() {
            if (field == null) {
                field = "Automatically set"
            }
            return field
        }


}
Run Code Online (Sandbox Code Playgroud)

尝试一下:

fun main() {
    val foo = Foo()
    foo.bar = "Manually set"
    println(foo.bar)
    foo.bar = null
    println(foo.bar)
}
Run Code Online (Sandbox Code Playgroud)

遗憾的是,该属性必须可以为空,才能使其正常工作.你必须使用!!?.在任何地方.


您也可以使用委托.这需要更多代码来编写属性,但可以更容易地在其他地方使用该属性.

class Foo(initBar: String? = null) {

    private val barDelegate = NullDelegate(initBar) { "Automatically set" }
    var bar: String by barDelegate // not nullable to outside world

    fun clearBar() {
        barDelegate.clear()
    }

}

// Reusable. Not thread-safe.
class NullDelegate<T>(
    private var value: T? = null, 
    private val supplier: () -> T
) {

    operator fun getValue(thisRef: Any?, property: KProperty<*>): T {
        if (value == null) value = supplier()
        return value!!
    }

    operator fun setValue(thisRef: Any?, property: KProperty<*>, value: T?) {
        this.value = value
    }

    fun clear() {
        value = null
    }

}
Run Code Online (Sandbox Code Playgroud)

设置barnull你打电话foo.clearBar()而不是foo.bar = null.