web-dev-qa-db-ja.com

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()?)

しかし、それはコンパイルされません。

29
Bryan

nullを受け取るときに同じデフォルト値を使用する セカンダリコンストラクター を作成できます。

data class Data(
        val name: String = "",
        val number: Long = 0
) {
    constructor(
            name: String? = null,
            number: Long? = null
    ) : this(
            name ?: "",
            number ?: 0
    )
}
25
mfulton26

セカンダリコンストラクターは、Nullableプリミティブプロパティのみをサポートします。つまり、プロパティがプリミティブ型ではない場合、2つの同じコンストラクターになります。たとえば、

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 ?: "")
    }
}

[〜#〜] if [〜#〜]クラスはデータクラスではないため、プライマリコンストラクターでプロパティを定義するのではなく、パラメーターからプロパティを遅延初期化できます。次に例を示します。

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