связать модификатор 'lateinit' с условием в Котлине - PullRequest
0 голосов
/ 05 марта 2019

В Kotlin у нас есть модификатор lateinit для отложенной инициализации переменной вместо var something: Something? = null.

В моей ситуации у меня есть список Element, и я хочу присвоить его переменной lateinit, когда у меня есть первый объект.

Итак, я попробовал несколько методов для достижения этой цели.

Первый , используя методы 'firstOrNull ()'

lateinit var applicationHolder: ApplicationHolder

applicationHolder = env.getElementsAnnotatedWith(InjectApplication::class.java)
        .map {
            ApplicationHolder(it, (it as TypeElement).asClassName(), it.simpleName.toString()).apply {
                val component = it.getAnnotation(InjectApplication::class.java).getComponent()
                componentClass = component
            }
        }.firstOrNull()

Первое решение не удалось, потому что applicationHolderне принимает Nullable тип ApplicationHolder.(Вывод типа не выполнен. Ожидаемое несоответствие типов: предполагаемый тип - ApplicationHolder? Но ожидаемый ApplicationHolder.)

Хотя я могу использовать first вместо firstOrNull, чтобы достичь этого, это слишком опасно, поскольку список может бытьпусто.

Second , с использованием условия if

val item = env.getElementsAnnotatedWith(InjectApplication::class.java)
        .map {
            ApplicationHolder(it, (it as TypeElement).asClassName(), it.simpleName.toString()).apply {
                val component = it.getAnnotation(InjectApplication::class.java).getComponent()
                componentClass = component
            }
        }.firstOrNull()

if (item != null) {
    applicationHolder = item
}

Второе решение успешно скомпилировано и работает.

Третье, используя свойства поддержки (на самом деле, это решение не использует модификатор lateinit)

val applicationHolder: ApplicationHolder
    get() {
        return _applicationHolder ?: throw NullPointerException("Not initialized")
    }

private var _applicationHolder: ApplicationHolder? = null

_applicationHolder = env.getElementsAnnotatedWith(InjectApplication::class.java)
        .map {
            ApplicationHolder(it, (it as TypeElement).asClassName(), it.simpleName.toString()).apply {
                val component = it.getAnnotation(InjectApplication::class.java).getComponent()
                componentClass = component
            }
        }.firstOrNull()

Третье решение успешно скомпилировано и работает хорошо.

Короче, мой вопросвыглядит следующим образом.

  1. Есть ли лучшее решение для достижения моей цели, чем эти решения?
  2. Если другого решения не существует, какое решение является чистым или лучшим?Я могу использовать второе или третье решение, но у меня нет уверенности, что оно чистое или лучше.

Ответы [ 2 ]

0 голосов
/ 05 марта 2019

Можно проверить, инициализирован ли lateinit, вызвав this::applicationHolder.isInitialized.(Это было введено в Kotlin 1.2; info здесь .)

Однако, согласно ответу @ user8159708, оно все еще пахнет немного.Переработка, чтобы сделать свойство обнуляемым, сделает его более неудобным для доступа, но намного безопаснее.

0 голосов
/ 05 марта 2019

Почему вы используете lateinit над обнуляемым типом здесь?

Это звучит как предупреждение для меня:

это слишком опасно, потому что список может быть пустым.

Если вы попытаетесь получить доступ к объекту lateinit без его инициализации, ваше приложение будет аварийно завершено.Следует использовать Lateinit, если он обязательно будет инициализирован.

Я бы изменил код на то, чего вы избегали: var something: Something? = null

Затем используйте метод firstOrNull ().Система безопасности с нулевым типом kotlin заставит вас иметь дело с нулями, что приведет к безопасному коду!

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