Sorting 将参数排序为变量

Sorting 将参数排序为变量,sorting,lambda,collections,kotlin,Sorting,Lambda,Collections,Kotlin,我有一个方法,需要以多种可能的方式对集合进行排序。与多次调用myCollection.sortedBy不同,我希望将传递给sortedBy的lambda作为变量,然后将该变量传递给一个调用sortedBy。但是,我无法确定lambda变量应该具有的类型。请记住,“按字段排序”可能有不同的类型(但它们显然都是可比较的) 以下是我的问题的简化版本: data class Person(val name: String, val age: Int) enum class SortBy { N

我有一个方法,需要以多种可能的方式对集合进行排序。与多次调用
myCollection.sortedBy
不同,我希望将传递给
sortedBy
的lambda作为变量,然后将该变量传递给一个调用
sortedBy
。但是,我无法确定lambda变量应该具有的类型。请记住,“按字段排序”可能有不同的类型(但它们显然都是可比较的)

以下是我的问题的简化版本:

data class Person(val name: String, val age: Int)

enum class SortBy {
    NAME, AGE
}

fun main(args: Array<String>) {
    val people = listOf(Person("John", 30), Person("Mary", 20))
    val sort = SortBy.NAME

    val comparator = when (sort) {
        SortBy.NAME -> { p: Person -> p.name }
        SortBy.AGE -> { p: Person -> p.age }
    }

    // the line below won't compile
    people.sortedBy(comparator).forEach(::println)
}
数据类人员(val name:String,val age:Int)
枚举类排序{
姓名、年龄
}
趣味主线(args:Array){
val people=listOf(个人(“约翰”,30岁),个人(“玛丽”,20岁))
val sort=SortBy.NAME
val比较器=何时(排序){
SortBy.NAME->{p:Person->p.NAME}
SortBy.AGE->{p:Person->p.AGE}
}
//下面这行代码无法编译
people.sortedBy(comparator).forEach(::println)
}

有什么想法吗?

问题是两个lambda有非常不同的类型,因此变量
comparator
的类型被简单地推断为
Any
,这是第一个常见的超类型。如果您需要能够为该变量分配任意一个lambda,则该变量没有其他类型(除了
Any?

然后,根据您得到的结果(一个
(Person)->Int
或一个
(Person)->String
),
sortedBy
方法必须以某种方式推断其类型参数,这在处理这两种情况时同样是不可能的


然而,有一个解决办法。您可以在不同的
分支中创建
Comparator
实例,而不是在
分支中创建
Comparator
实例,该分支包装了将
人员
实例进行比较的特定类型,函数为:

val comparator: Comparator<Person> = when (sort) {
    SortBy.NAME -> compareBy { it.name }
    SortBy.AGE -> compareBy { it.age }
}

您可以简单地使用属性引用

val people = listOf(Person("John", 30), Person("Mary", 20))
val sort = Person::age
people.sortedBy(sort).forEach(::println)

谢谢这非常有效。我以前不知道
compareBy
。关键是让变量
sort
能够以不同的类型保存
Person::age
Person::name
等。这就是为什么我的示例在
场景中出现了
(真实场景比只按一个字段进行硬编码排序更复杂)。这种解决方案在那种情况下行不通。
val people = listOf(Person("John", 30), Person("Mary", 20))
val sort = Person::age
people.sortedBy(sort).forEach(::println)