Kotlin带有接收者的函数类型(block: T.() -> Unit)

前言

Kotlin标准库的 Standard.kt 包含几个函数,其唯一目的是在对象上下文内执行代码块。 当我们在提供了lambda表达式的对象上调用此类函数时,它将形成一个临时作用域。在此作用域中,我们可以访问没有其名称的对象,这些功能称为作用域函数。

比如我们经常使用的 applyalso 函数:

public inline fun <T> T.apply(block: T.() -> Unit): T {
    contract {
        callsInPlace(block, InvocationKind.EXACTLY_ONCE)
    }
    block()
    return this
}
public inline fun <T> T.also(block: (T) -> Unit): T {
    contract {
        callsInPlace(block, InvocationKind.EXACTLY_ONCE)
    }
    block(this)
    return this
}

如果我们仔细比较这两个扩展函数会发现它们非常相似:它们都接收一个 block 函数并返回 this 值。

唯一的差别就在于 apply 的 block 函数类型为:T.() -> Unit ,而 also 的 block 函数类型为:(T) -> Unit)

那么这两种函数类型到底差别在哪里呢 ?

T.() -> Unit(T) -> Unit)

首先我们看下

class Test {

    fun main(block: Int.() -> Unit) {
    
        val also: Class<Test> = javaClass.also {
            val canonicalName = it.canonicalName
            println(canonicalName)
        }
        
        val apply: Class<Test> = javaClass.apply {
            println(canonicalName)
        }
    }
}

这样看起来不太明显,我们看下AndroidStudio的智能提示:
智能提示
这样看起来是不是简单多了,在 also 方法中接收到的是 it , 而在 apply 方法中接收到的是 this ,而表达式 it.canonicalNamecanonicalName 的差别不用我说了吧。

applythis 值作为接收者调用指定的函数[block],并返回 this 值。

alsothis 值作为参数调用指定的函数[block],并返回 this 值。

参数我们都理解,但是接收者是个什么概念,貌似从来没听过?

Kotlin的函数类型

Kotlin 使用类似 (Int) -> String 的一系列函数类型来处理函数的声明:val onClick: () -> Unit = ……

这些类型具有与函数签名相对应的特殊表示法,即它们的参数和返回值:

  • 所有函数类型都有一个圆括号括起来的参数类型列表以及一个返回类型:(A, B) -> C 表示接受类型分别为 A 与 B 两个参数并返回一个 C 类型值的函数类型。 参数类型列表可以为空,如 () -> AUnit 返回类型不可省略。
  • 函数类型可以有一个额外的接收者类型,它在表示法中的点之前指定类型: A.(B) -> C 表示可以在 A 的接收者对象上以一个 B 类型参数来调用并返回一个 C 类型值的函数。 带有接收者的函数字面值通常与这些类型一起使用。
  • 挂起函数属于特殊种类的函数类型,它的表示法中有一个 suspend 修饰符 ,例如 suspend () -> Unit 或者 suspend A.(B) -> C

函数类型表示法可以选择性地包含函数的参数名:(x: Int, y: Int) -> Point。 这些名称可用于表明参数的含义。

带有接收者的函数类型

带有接收者的函数类型,例如 A.(B) -> C,可以用特殊形式的函数字面值实例化—— 带有接收者的函数字面值

Kotlin 提供了调用带有接收者(提供接收者对象)的函数类型实例的能力。

在这样的函数字面值内部,传给调用的接收者对象成为隐式的 this,以便访问接收者对象的成员而无需任何额外的限定符,亦可使用 this 表达式 访问接收者对象

这种行为与扩展函数类似,扩展函数也允许在函数体内部访问接收者对象的成员。

为了表示当前的 接收者 我们使用 this 表达式:

  • 在类的成员中,this 指的是该类的当前对象。
  • 在扩展函数或者带有接收者的函数字面值中, this 表示在点左侧传递的 接收者 参数。
//Lambda 表达式(函数字面值)
val sum2: Int.(Int) -> Int = { other ->
    plus(other) //这里直接调用了Int的plus()方法,也可以写成 this.plus(other)
}

当接收者类型可以从上下文推断时,lambda 表达式可以用作带接收者的函数字面值。

参考

Kotlin:带有接收者的函数字面值

Kotlin:作用域函数

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值