Создавать переменную в Kotlin, только если она нулевая? - PullRequest
0 голосов
/ 07 февраля 2019

Допустим, у меня есть переменная:

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.Пожалуйста, помогите мне с решением и объяснением.спасибо вперед

Ответы [ 5 ]

0 голосов
/ 08 февраля 2019

Вы почти нашли правильный ответ с помощью оператора elvis, единственной недостающей частью было присвоить вновь созданному экземпляру обратно переменную myObject:

private fun getMyObject() = myObject ?: MyObject().also { myObject = it }
0 голосов
/ 07 февраля 2019

Проблема в том, что метод получения и установки свойства не может иметь разные типы.Я бы предложил отдельное частное свойство, которое может быть пустым, и способ его очистки:

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
}

Если вам нужен этот шаблон более одного раза, напишите делегат .

0 голосов
/ 07 февраля 2019

Вы можете использовать вспомогательное поле свойства.

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.

0 голосов
/ 07 февраля 2019

Ответ:

Более короткая версия версии @ 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.

0 голосов
/ 07 февраля 2019

Вы можете объединить Java-подобный подход с использованием оператора Элвиса, написав что-то вроде этого:

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

Явное преобразование as MyObject необходимо из-за объявления myObject: var myObject MyObject? = null.myObject является обнуляемым MyObject, но getObject возвращает тип MyObject.Я надеюсь, что это может помочь вам!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...