Kotlin 将具有可空字段的对象转换为具有不可空字段或空字段的对象

Kotlin 将具有可空字段的对象转换为具有不可空字段或空字段的对象,kotlin,Kotlin,我有一个API返回的对象,它有不同的可空字段。 我想创建另一个具有不可为null的字段的对象,如果不可能,则返回null。最适合这种情况的语言习惯用法是什么?目前我正在使用?.let{},它看起来很难看: fun convertAnswer(userAnswer: AnswerGson, answerResponse: AnswerResponseGson, correctAnswerText: String): AnswerResponseUi? {

我有一个API返回的对象,它有不同的可空字段。 我想创建另一个具有不可为null的字段的对象,如果不可能,则返回null。最适合这种情况的语言习惯用法是什么?目前我正在使用?.let{},它看起来很难看:

fun convertAnswer(userAnswer: AnswerGson, answerResponse: AnswerResponseGson,
                  correctAnswerText: String): AnswerResponseUi? {
    return userAnswer.id?.let { userAnswerId ->
        userAnswer.text?.let { userAnswerText ->
            answerResponse.answer?.id?.let { correctAnswerId ->
                answerResponse.points?.let { points ->
                    answerResponse.discount?.let { discount ->
                        answerResponse.booster?.let { booster ->
                            return AnswerResponseUi(userAnswerId, correctAnswerId, userAnswerText,
                                    correctAnswerText, points, discount, booster.name ?: "")
                        }
                    }
                }
            }
        }
    }
}
如果类AnswerGson和AnswerResponseGson的属性声明为val,则可以将代码转换为如下内容:

fun convertAnswer(userAnswer: AnswerGson, answerResponse: AnswerResponseGson,
                  correctAnswerText: String): AnswerResponseUi? {
    if (userAnswer.id == null ||
        userAnswer.text == null ||
        answerResponse.discount == null ||
        answerResponse.points == null ||
        answerResponse.booster == null ||
        answerResponse.answer == null ||
        answerResponse.answer.id == null
    ) return null

    return AnswerResponseUi(userAnswer.id, answerResponse.answer.id, userAnswer.text,
                            correctAnswerText, answerResponse.points,
                            answerResponse.discount, answerResponse.booster.name ?: "")
}
本例使用:编译器分析控制流,并证明如果达到最后一条语句,则上面检查的值都不为null

这些检查不适用于安全解除引用链,我必须先检查answerResponse.answer,然后才检查answerResponse.answer.id

如果您具有var属性,则无法应用智能强制转换,因为该值在选中后可能会更改

在这种情况下,您仍然可以通过将值提取到局部变量并同时检查它们来减少代码中的嵌套:

fun convertAnswer(userAnswer: AnswerGson, answerResponse: AnswerResponseGson,
                  correctAnswerText: String): AnswerResponseUi? {
    val answerId = userAnswer.id ?: return null
    val correctAnswerId = answerResponse.answer?.id ?: return null
    val userAnswerText = userAnswer.text ?: return null
    val points = answerResponse.points ?: return null
    val discount = answerResponse.discount ?: return null
    val booster = answerResponse.booster ?: return null

    return AnswerResponseUi(answerId, correctAnswerId, userAnswerText,
                            correctAnswerText, points,
                            discount, booster.name ?: "")
}
而且,正如所注意到的,您甚至可以内联这些变量,它们也适用于VAL:

fun convertAnswer(userAnswer: AnswerGson, answerResponse: AnswerResponseGson,
                  correctAnswerText: String): AnswerResponseUi? {
    return AnswerResponseUi(userAnswer.id ?: return null, 
                            answerResponse.answer?.id ?: return null, 
                            userAnswer.text ?: return null,
                            correctAnswerText, 
                            answerResponse.points ?: return null,
                            answerResponse.discount ?: return null, 
                            (answerResponse.booster ?: return null).name ?: "")
}

哇!我刚刚意识到,如果您不需要,所有这些局部变量甚至都可以内联。例如。。。return-answerresponseiuseranswer.id?:return null,answerResponse.answer?.id?:return null,…可读性是关键,所以不要尝试内联所有内容;但这确实令人印象深刻!