可以说,我有一个变量:
var myObject : MyObject? = null
应该在某个地方清除它:
myObject?.clear
myObject = null
,并且在使用位置绝对不能为空。在Java中,我可以执行以下操作:
private MyObject getMyObject(){
if(myObject == null) {
myObject = new MyObject()
}
return myObject
}
问题:如何在Kotlin中实现这一目标?
我发现了使用Elvis-operator的建议:
private fun getMyObject() = myObject ?: MyObject()
,但这不会将结果(如果将创建MyObject
的新实例)分配给myObject
变量。
请帮助我解决方案和解释。谢谢你
答案 0 :(得分: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。
答案 1 :(得分: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
}
}
要将bar
设置为null
,您将呼叫foo.clearBar()
而不是foo.bar = null
。
答案 2 :(得分:2)
答案:
以下是@Slaw版本的较短版本:
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
。
答案 3 :(得分:1)
您可以将类似Java的方法与Elvis运算符的用法结合使用,编写如下代码:
private fun getMyObject() : MyObject {
myObject = myObject ?: MyObject()
return myObject as MyObject
}
由于as MyObject
的声明:myObject
,因此需要进行显式转换var myObject MyObject? = null
。 myObject
是可为空的MyObject
,但是getObject
的返回类型为MyObject
。
希望对您有所帮助!
答案 4 :(得分:1)
使用elvis运算符几乎可以找到正确的答案,唯一缺少的部分是将新创建的实例分配回myObject
变量:
private fun getMyObject() = myObject ?: MyObject().also { myObject = it }