如何简化 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
- 作用域函数
run {}
在一个对象上被调用 student
equals
替换为 ==
以比较布尔值和 null
值
- 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]
我有一个谓词从句链,像这样
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
- 作用域函数
run {}
在一个对象上被调用student
equals
替换为==
以比较布尔值和null
值- 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]