如何简化 Kotlin 中的谓词链

How to simplify chain of predicates in Kotlin

我有一个谓词从句链,像这样

student?.firstName?.equals("John") ?: false &&
student?.lastName?.equals("Smith") ?: false &&
student?.age?.equals(20) ?: false &&
student?.homeAddress?.equals("45 Boot Terrace") ?: false &&
student?.cellPhone?.startsWith("123456") ?: false

我发现可以切换到布尔谓词 and() 而不是 &&,但总的来说它不会代码更简洁。

Kotlin 有没有办法简化这样的表达式?

例如

val result = listOf(
    student.firstName == "John",
    student.lastName == "Smith",
    student.age == 20,
    student.cellPhone.orEmpty().startsWith("123456")
).all { it }

fun isAllTrue(first: Boolean, vararg other: Boolean): Boolean {
    return first && other.all { it }
}

val result = isAllTrue(
    student.firstName == "John",
    student.lastName == "Smith",
    student.age == 20,
    student.cellPhone.orEmpty().startsWith("123456")
)

fun Iterable<Boolean>.isAllTrue(): Boolean {
    return all { it }
}

val result = listOf(
    student.firstName == "John",
    student.lastName == "Smith",
    student.age == 20,
    student.cellPhone.orEmpty().startsWith("123456")
).isAllTrue()

感谢大家的参与!这是带有注释的代码的最终版本:

student?.run {
  firstName == "John" &&
  lastName == "Smith" &&
  age == 20 &&
  homeAddress == "45 Boot Terrace" &&
  cellPhone.orEmpty().startsWith("123456")
} ?: false
  1. 作用域函数 run {} 在一个对象上被调用 student
  2. equals 替换为 == 以比较布尔值和 null
  3. return 类型的作用域函数可以为空,因此使用了 elvis 运算符 ?: false。另一种选择是使用 == true,但这是您的个人喜好

不完全是 OP 想要的,但似乎这里的问题是比较两个 Student 类型的对象,而不是链接谓词。

不确定用例是什么,但这里有一个更面向对象的解决方案,我们将谓词放在 Student::isSimilarToJohn 下(因为我假设这个 John Smith 很特别):

data class Student(
    val firstName: String?,
    val lastName: String?,
    val age: Int?,
    val homeAddress: String?,
    val cellPhone: String?,
) {
    fun isSimilarToJohn(): Boolean {
        return firstName == "John" &&
            lastName == "Smith" &&
            age == 20 &&
            homeAddress == "45 Boot Terrace" &&
            cellPhone.orEmpty().startsWith("123456")
    }
}

示例:

val students = listOf(
    Student("John", "Smith", 20, "45 Boot Terrace", "1234568"),
    Student("John", "Smith", 20, "45 Boot Terrace", "1234567"),
    Student("Mary", "Smith", 20, "45 Boot Terrace", "1234567"),
    Student("John", "Doe",   20, "45 Boot Terrace", "1234567"),
)
students.map { it.isSimilarToJohn() }
// [true, true, false, false]