member reference in Kotlin(::)


class Student(val id: Int, val name: String)
fun main() {
val list = arrayListOf<Student>(Student(200, "Lim"), Student(100, "Kim"), Student(300, "Park"))
println(list.map { Student::name })
println(list.map { student -> student.name })
}

结果:

[val Student.name: kotlin.String, val Student.name: kotlin.String, val Student.name: kotlin.String]
[Lim, Kim, Park]

我不明白为什么会这样。

让我们来看看String::name到底是什么。这是一个KProperty1<Student, String>.此接口也实现了(Student) -> String。因此,我们实际上是在处理一个 lambda,它将Student作为参数并返回一个String

现在,map函数需要什么?map函数采用一个将某种类型映射到另一种类型的lambda((T) -> R(,这意味着我们可以Student::name传递给它。像任何函数一样,您将参数放在括号内。

list.map(Student::name) // variant 1

如果你想定义自己的lambda,你可以这样做:

val lambda: (Student) -> String = { it.name }
list.map(lambda) // variant 2

请注意 lambda 是如何作为参数在括号内传递的。如果您内联 lambda,则可以省略这些括号(并且 lambda 是该函数的最后一个参数(:

list.map { it.name } // variant 3

让我们看看你发生了什么。您在 lambda 中传递了引用:

list.map { Student::name }

这意味着您将列表中的任何元素转换为 Name 属性的引用。因此,您想要的是变体 1、2 或 3。

如注释中所述,您的第一个map操作将引用映射到class Studentname字段的引用,然后打印该字段。
第二个映射每个Student实例的该字段的值。

您可以使用字段引用来映射值,但必须为其使用略有不同的语法:map(...)而不是map{ ... },请参阅以下示例:

fun main(args: Array<String>) {
val list = arrayListOf<Student>(Student(200, "Lim"), Student(100, "Kim"), Student(300, "Park"))
// map and print field reference of the class
println(list.map { Student::name })
// map and print field reference for each instance by lambda expression
println(list.map { student -> student::name })
// map and print values by field reference for each instance
println(list.map(Student::name))
// map and print values by transformation for each instance by lambda expression
println(list.map { student -> student.name })
}

因此,输出为

[val de.os.kotlin.Student.name: kotlin.String, val de.os.kotlin.Student.name: kotlin.String, val de.os.kotlin.Student.name: kotlin.String]
[val de.os.kotlin.Student.name: kotlin.String, val de.os.kotlin.Student.name: kotlin.String, val de.os.kotlin.Student.name: kotlin.String]
[Lim, Kim, Park]
[Lim, Kim, Park]

相关内容

最新更新