实例在科特林一个变量,只有当它是一个空?

问题描述 投票:3回答:5

比方说,我有一个变量:

var myObject : MyObject? = null

它应该在一些地方被清除:

myObject?.clear
myObject = null

并应在一个地方使用的绝对不可为空。在Java中,我可以做这样的事情:

private MyObject getMyObject(){
  if(myObject == null) {
    myObject = new MyObject()
  }
  return myObject
}

问题:我如何才能做到在科特林?

我发现了一个建议,使用猫王操作:

private fun getMyObject() = myObject ?: MyObject()

但是,这并不分配结果(如果MyObject的新实例将被创建)到myObject变量。请帮我解决和解释。提前感谢

java kotlin nullable getter backing-field
5个回答
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
}

如果您需要这种模式不止一次,写delegate


5
投票

您可以使用属性的backing field

class Foo {

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


}

要尝试:

fun main() {
    val foo = Foo()
    foo.bar = "Manually set"
    println(foo.bar)
    foo.bar = null
    println(foo.bar)
}

不幸的是,属性必须为空的这个工作。你将不得不使用!!?.随处可见。


你也可以使用一个委托。这需要更多的代码写的属性,但更容易在其他地方使用该属性。

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
    }

}

要设置barnull你会改为调用foo.clearBar()foo.bar = null


2
投票

回答:

动@色拉的版本更短的版本如下:

var myObject: MyObject? = null
    get() {
        field = field ?: MyObject()
        return field
    }

如果该属性是一个MyObject访问null这将实例化一个新get的支持字段。


附加信息:

你可能会想到类似于以下一个较短的版本

var myObject: Any? = null
    get() = field = field ?: Any() // Does not compile

请记住,这不符合该错误消息编译:Assignments are not expressions, and only expressions are allowed in this context


1
投票

您可以使用Elvis操作符的使用结合类似Java的方法,写这样的事情:

private fun getMyObject() : MyObject {
    myObject = myObject ?: MyObject()
    return myObject as MyObject
}

需要因为as MyObject的声明的显式转换myObjectvar myObject MyObject? = nullmyObject是一个可空MyObjectgetObject的返回类型为MyObject。我希望这可以帮助你!


1
投票

你几乎找不到具有猫王操作正确的答案,唯一缺少的部分是新创建的实例分配回myObject变量:

private fun getMyObject() = myObject ?: MyObject().also { myObject = it }
© www.soinside.com 2019 - 2024. All rights reserved.