инициализация val с использованием функций области видимости kotlin и оператора элвиса

#kotlin

Вопрос:

Я хочу инициализировать два val в зависимости от того, является ли третья переменная нулевой или нет. Это работает:

 class ABC(input: String?) {
    private val x: Int
    private val y: Int
    
    init {
        if (input != null) {
            x = 1
            y = 1
        } else {
            x = 2
            y = 2
        }
    }
}
 

Но это не компилируется:

 class ABC(input: String?) {
    private val x: Int
    private val y: Int

    init {
        input?.also {
            x = 1
            y = 1
        } ?: also {
            x = 2
            y = 2
        }
    }
}
 

Почему второй пример приводит к ошибке? Разве логически это не то же самое, что и первое? Каков наиболее краткий способ достижения результата?

Ответ №1:

Он логически оценивает то же самое для людей, но слишком сложен для компилятора. Компилятор может обрабатывать одно if/else, но цепочка нулей и оператор Элвиса подобны двум отдельным операторам if. Ваш второй блок кода в основном похож на следующий, на который компилятор также будет жаловаться:

 if (input != null) {
    x = 1
    y = 1
}
if (input == null) {
    x = 2
    y = 2
}
 

Цепочка функций области, подобных этой, в любом случае подвержена ошибкам, и ее следует избегать, когда это возможно. Ваш первый блок кода намного превосходит второй по удобочитаемости. Когда вы работаете со свойствами, допускающими обнуление, или вызываете ряд функций в стиле конструктора, тогда функции с цепочкой областей могут быть хорошим выбором. Но в данном случае input это не свойство, поэтому вы можете написать более декларативный (т. Е. Более читаемый) код без цепочки функций области действия.

Я думаю, что это самый краткий способ инициализации ваших двух переменных, как вы их определили:

 class ABC(input: String?) {
    private val x: Int = if (input != null) 1 else 2
    private val y: Int = x
}