Kotlin 带接收者的函数 implicit receiver 隐式接收者
目录
Kotlin 带接收者的函数 implicit receiver 隐式接收者
隐式接收者的概念
implicit receiver,既隐式接收器或者隐式接收者,接受函数的调用和属性的访问。
在 Java 中这个隐式的接收者其实就是 this。而 kotlin 对它进行了一些关键性的拓展,在拓展的同时,为了方便描述和沟通,给它起了专属的名字:implicit receiver。
比如在 Java 中,可以隐式的调用内部类和外部类的成员变量,kotlin 同理。
kotlin 特殊的点在于,他可以直接通过函数来嵌套新的 this。
场景一: 用于省略代码
例如有一个对象 user,当我们访问其成员时,需要使用 user.xxx:
data class User(var name: String, var blog: String)
val user = User("bqt", ".blog.com")
println(user.name + user.blog) // 需要显示调用 user
如果我们想省略掉 user,有什么办法可以实现呢?
使用自带的 apply 函数
最简单的方式,借助自带的 apply 就可以实现:
user.apply {
println(name + this.blog) // apply 的闭包中可以使用 this 代替 user,this 可以省略
}
使用普通的扩展函数
如果不使用自带的 apply,有什么办法可以实现呢?
现在,我们尝试使用普通的扩展函数,自己实现这个 apply 方法:
fun User.apply2(block: (user: User) -> Unit): User {
block(this)
return this
}
user.apply2 {
println(it.name + it.blog) // 只能通过 it 访问成员,而不能通过 this 访问成员
}
可以发现,我们自定义的 apply2 并不能通过 this 访问成员,所以不能满足我们的要求。
使用带接收者的扩展函数
使用带接收者的扩展函数,则可以满足我们的要求。
fun User.apply3(block: User.() -> Unit): User { // 把参数提取到了外面
block() // 不用再传 this
return this
}
核心变化:把参数类型 User 提取到了参数列表外面
user.apply3 {
println(this.name + blog) // 可以通过 this 访问成员了
}
可以发现,此时,apply3 和自带的 apply 的效果完全一致了。
方法对比

场景二:提供上下文环境
现在定义这样一个类 User,它的内部有个扩展函数 getUserName():
data class User(private var name: String) {
fun String.getUserName(): String = "[$name.$this]"
}
这个扩展函数在外部是无法被调用它的,如果想调用,必须想办法创造一个 User 的环境。
这里写了一个 runAsUser 的函数,传进去一个函数类型的参数 block,又设置 block 的 receiver User,这样就强行插入了一个 User 的 this。
data class User(private var name: String) {
fun String.getUserName(): String = "[$name.$this]"
fun runAsUser(block: User.() -> Unit) {
block()
}
}
这样就可以通过这个函数来进行调用了:
fun main() {
val user = User("bqt")
user.runAsUser {
println("白乾涛".getUserName()) // 可以调用这个扩展函数了
}
}
所以,他的作用就是,提供一个 User 的上下文环境,在这个环境中,就可以调用 User 的成员了。
2017-06-07
本文来自博客园,作者:白乾涛,转载请注明原文链接:https://www.cnblogs.com/baiqiantao/p/6955536.html

浙公网安备 33010602011771号