Есть ли способ использовать значение по умолчанию для необязательных параметров, когда передается значение null?

Например, если у меня есть следующий класс данных:

data class Data(
    val name: String = "",
    val number: Long = 0
)

И функции, которые могут возвращать null:

fun newName(): String? {}

fun newNumber(): Long? {}

Я знаю, что могу использовать следующее, чтобы использовать значение функций, если они не null:

val newName = newName()
val newNumber = newNumber()

val data = Data(
        if (newName != null) newName else "",
        if (newNumber != null) newNumber else 0
)

Но есть ли способ просто использовать значение по умолчанию, указанное в конструкторе класса Data, когда значения равны null?

Я не мог найти ничего в документации, но я надеялся, что что-то вроде этого будет работать:

val data = Data(newName()?, newNumber()?)

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


person Bryan    schedule 23.06.2017    source источник
comment
Вместо if (newName != null) newName else "" можно просто использовать newName ?: "". Это называется оператор Элвиса.   -  person Mibac    schedule 23.06.2017
comment
@Mibac Ах да, я и забыл об этом! Определенно более краткий, но он по-прежнему не использует параметр по умолчанию, определенный в конструкторе класса.   -  person Bryan    schedule 23.06.2017


Ответы (2)


Вы можете определить сопутствующий объект для вашего класса данных и перегрузить его вызов оператора для использования значений по умолчанию при передаче null:

data class Data private constructor(
    val name: String,
    val number: Long
) {
    companion object {
        operator fun invoke(
            name: String? = null,
            number: Long? = null
        ) = Data(
            name ?: "",
            number ?: 0
        )
    }
}
person mfulton26    schedule 23.06.2017
comment
О, это хороший обходной путь! Хотя мне хочется, чтобы что-то подобное было встроено в язык; если только избавиться от шаблона. - person Bryan; 23.06.2017
comment
Будет ли это работать, если удалить все второе свойство (число)? Я получаю ошибку компиляции для data class Data(val name: String = "") { constructor(name: String? = null) : this(name ?: "") } - person eendroroy; 17.06.2020
comment
Я думаю, вам придется передать null или добавить еще один вторичный конструктор. например constructor(): this("") - person mfulton26; 18.06.2020
comment
@eendroroy Я понял, что этой двусмысленности разрешения перегрузки можно избежать, я соответствующим образом обновил свой ответ. - person mfulton26; 18.06.2020
comment
@ mfulton26 mfulton26 Он отлично работает, когда есть параметр number: Long. Но я думаю, что если мы оставим только параметр name: String, проблема возникнет. - person eendroroy; 18.06.2020
comment
@eendroroy, вы правы, я обнаружил, что использование объекта-компаньона с оператором вызова должно работать в обоих случаях, я соответствующим образом обновил свой ответ; т.е. теперь он будет работать без number: Long и оставить только name: String ???????? - person mfulton26; 18.06.2020

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

data class Data(val name: String) {
    constructor(name: String? = null) : this(name ?: "foo");
    // ^--- report constructor signature error                
}

data class Data(val number: Long = 0) {
     constructor(number: Long? = null) : this(number ?: 0)
     //                  ^--- No problem since there are 2 constructors generated:
     //                       Data(long number) and Data(java.lang.Long number)
}

альтернативный способ - использовать для этого оператор invoke, например:

data class Data(val name: String) {
    companion object {
        operator fun invoke(name: String? = null) = Data(name ?: "")
    }
}

ЕСЛИ класс не является классом данных, тогда вы можете лениво инициализировать свойства из параметров, а не определять свойства в основном конструкторе, например:

class Data(name: String? = null, number: Long? = null) {
    val name = name ?: ""
    val number = number ?: 0
}
person holi-java    schedule 24.06.2017