英文:
How to combine lambdas in Kotlin
问题
我目前正在尝试比较Java的lambda与Kotlin的lambda。我认为Kotlin的一个优势是不需要使用函数式接口来创建lambda表达式。在Java中,要想很好地使用lambda表达式和集合操作,需要对所有函数式接口有一个相对清晰的概览。
但是在我的研究中,我也找到了一个负面的观点。我认为Java中的Predicate有一个默认函数,它可以让你组合一些lambda表达式。
所以在Java中,你可以像这样做:
final Predicate<Person> isAdult = person -> person.getAge() >= 18;
final Predicate<Person> isMale = person -> person.getGender() == Gender.MALE;
// 组合
final Predicate<Person> isAdultAndMale = isAdult.and(isMale);
我认为在Kotlin中没有相等的功能。我在《Head First Kotlin》中读到有一个combine函数。但在Kotlin Playground中它不起作用。所以我最终使用了一个扩展函数,分别为两个lambda和多于两个lambda写了两个扩展函数,后者使用了varargs。
enum class Gender { MALE, FEMALE }
enum class EyeColor { BLUE, GREEN }
data class Person(
var name: String,
var age: Int,
var gender: Gender,
var eyeColor: EyeColor
)
fun List<Person>.combineTwoLambdas(firstLambda: (Person) -> Boolean, secondLambda: (Person) -> Boolean): List<Person> {
return this.filter(firstLambda).filter(secondLambda)
}
fun List<Person>.combineMoreLambdas(vararg personFilters: (Person) -> Boolean): List<Person> {
var myPersons = listOf<Person>()
personFilters.forEach {
myPersons = this.filter(it)
}
return myPersons
}
typealias PredicatePersons = (Person) -> Boolean
fun main() {
val persons = listOf(
Person("Susi", 20, Gender.FEMALE, EyeColor.BLUE),
Person("Ralf", 19, Gender.MALE, EyeColor.BLUE),
Person("Michael", 20, Gender.MALE, EyeColor.GREEN)
)
val isAdult: (Person) -> Boolean = { person -> person.age >= 18 }
val isMale: (Person) -> Boolean = { it.gender == Gender.MALE }
val hasGreenEyes: PredicatePersons = { it.eyeColor == EyeColor.GREEN }
// 组合两个lambda
val isAdultAndMale = persons.combineTwoLambdas(isAdult, isMale)
// 组合多于两个lambda
val isAdultAndMaleAndHasGreenEyes = persons.combineMoreLambdas(isAdult, isAdult, hasGreenEyes)
print("combine all $isAdultAndMaleAndHasGreenEyes")
}
是否有一种更简单地链接多个lambda的方法?谢谢。
更新
这里是更新,感谢@Sweeper的建议:
val isAdultAndMale: (Person) -> Boolean = { isAdult(it) && isMale(it) }
// 使用别名
val isAdultAndMale: PredicatePersons = { isAdult(it) && isMale(it) }
英文:
I am currently trying to compare Java lambdas with Kotlin lambdas. I think it is a advantage that kotlin doesnt need Functional Interfaces for creating a lambda. I think it is a little bit different to get an overview of all Funtional Interfaces in Java to use lambdas and collection manipulation very well.
But I found a negative point also during my research. I think a Predicate in Java has a default function and which lets you combine some lambdas.
So you can do something like this in Java:
final Predicate<Person> isAdult = person -> person.getAge() >= 18;
final Predicate<Person> isMale = person -> person.getGender() == Gender.MALE;
// Combine
final Predicate<Person> isAdultAndMale = isAdult.and(isMale);
I think there is now equivalent in Kotlin. I read in Head first Kotlin that there is a combine function. But it doesn't work in the Kotlin playground.
So I end up with an extension function. Respectively with two extension functions. One for two lambdas and another for more than two lambdas and with varargs.
enum class Gender{MALE, FEMALE}
enum class EyeColor{BLUE, GREEN}
data class Person(
var name: String,
var age: Int,
var gender: Gender,
var eyeColor: EyeColor
)
fun List<Person>.combineTwoLambdas(firstLambda: (Person) -> Boolean, secondLambda: (Person) -> Boolean): List<Person> {
return this.filter(firstLambda).filter(secondLambda)
}
fun List<Person>.combineMoreLambdas(vararg personFilters: (Person) -> Boolean): List<Person> {
var myPersons = listOf<Person>()
personFilters.forEach {
myPersons = this.filter(it)
}
return myPersons
}
typealias PredicatePersons = (Person) -> Boolean
fun main() {
val persons = listOf(
Person("Susi", 20, Gender.FEMALE, EyeColor.BLUE),
Person("Ralf", 19, Gender.MALE, EyeColor.BLUE),
Person("Michael", 20, Gender.MALE, EyeColor.GREEN))
val isAdult: (Person) -> Boolean = {person -> person.age >= 18}
val isMale: (Person) -> Boolean = {it.gender == Gender.MALE}
val hasGreenEyes: PredicatePersons = {it.eyeColor == EyeColor.GREEN}
// combine two lambdas
val isAdultAndMale = persons.combineTwoLambdas(isAdult, isMale)
// combine more than two lambdas
val isAdultAndMaleAndHasGreenEyes = persons.combineMoreLambdas(isAdult, isAdult, hasGreenEyes)
print("combine all ${isAdultAndMaleAndHasGreenEyes}")
}
Is it somehow easier to chain multiple lambdas? Thanks.
UPDATE
Here is an update. Thanks to @Sweeper
val isAdultAndMale: (Person) -> Boolean = {isAdult(it) && isMale(it)}
// with alias
val isAdultAndMale: PredicatePersons = {isAdult(it) && isMale(it)}
答案1
得分: 3
你可以轻松地定义 and
和 or
的等价扩展函数:
fun <T> ((T) -> Boolean).and(arg: (T) -> Boolean): (T) -> Boolean = { this(it) && arg(it) }
fun <T> ((T) -> Boolean).or(arg: (T) -> Boolean): (T) -> Boolean = { this(it) || arg(it) }
...
val isAdultAndMale = isAdult.and(isMale)
英文:
You can define equivalents of and
and or
easily as extension functions:
fun <T> ((T) -> Boolean).and(arg: (T) -> Boolean): (T) -> Boolean = { this(it) && arg(it) }
fun <T> ((T) -> Boolean).or(arg: (T) -> Boolean): (T) -> Boolean = { this(it) || arg(it) }
...
val isAdultAndMale = isAdult.and(isMale)
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论