End

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

posted @ 2017-06-07 09:58  白乾涛  阅读(13090)  评论(0)    收藏  举报