将具有可空字段的对象转换为具有非可空字段的对象或null

时间:2016-10-19 16:28:09

标签: kotlin

我有一个API返回的对象,它有不同的可空字段。 我想创建一个具有非可空字段的另一个对象,或者如果不可能则返回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 ?: "")
                        }
                    }
                }
            }
        }
    }
}

1 个答案:

答案 0 :(得分:4)

如果您的课程AnswerGsonAnswerResponseGson将其属性声明为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 ?: "")
}

此示例使用smart casts:编译器分析控制流并证明如果到达最后一个语句,则上面检查的值都不是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 ?: "")
}

并且,正如@mfulton26注意到的那样,您甚至可以内联这些变量(也适用于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 ?: "")
}