kotlin 使用扩展函数作为函数参数有什么好处?

oyxsuwqo  于 2022-12-13  发布在  Kotlin
关注(0)|答案(2)|浏览(169)

最近我仔细研究了Kotlin的作用域函数,发现有时候它们需要一个扩展函数作为参数,就以alsoapply为例:

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
}

从消费者的Angular 来看,这两者似乎没有太大的区别,我可以用几乎相同的方式称呼它们:

fun main() {
    val logger = Logger.getLogger("Test")
    logger.info("A").apply {
        logger.info("B")
    }.also {
        logger.info("C")
    }
}

所以我想知道我在这里遗漏了什么?在Kotlin中是否有一个模式或最佳实践,何时在高阶函数中使用扩展函数,以及它的确切好处是什么?

31moq8wy

31moq8wy1#

从消费者的Angular 来看,这两者似乎没有太大的区别,我可以用几乎相同的方式来称呼它们
这是因为你没有利用这里的接收器或参数,你使用的是现有的变量logger,而不是接收器apply提供的任何变量。
作用域函数的一个要点是,当你还没有变量时,可以在表达式中使用它们:

Logger.getLogger("Test").apply {
    info("A") // the logger is provided as `this` here
}

Logger.getLogger("Test2").also { logger ->
    logger.info("A") // the logger is provided as parameter here
}

Logger.getLogger("Test2").also {
    it.info("A") // using the implicit `it` parameter
}

正如你在上面的例子中可能注意到的,接受lambda和receiver的高阶函数将以不同的方式提供值给函数的调用者。在块中,如果是receiver,参数将以this的形式可用,否则将以参数的形式可用。

byqmnocz

byqmnocz2#

Logger.info的情况下,它们确实没有太大的不同。info返回Unit,所以TUnit,而Unit是一个相当糟糕的例子。
考虑一个更好的例子:

val person = Person().apply {
    firstName = "John"
    lastName = "Smith"
    age = 30
}

// vs

val person = Person().also {
    it.firstName = "John"
    it.lastName = "Smith"
    it.age = 30
}

这两个语句都做同样的事情,即下面的语句,但是在一个语句中:

val person = Person()
person.firstName = "John"
person.lastName = "Smith"
person.age = 30

但是因为apply的lambda是一个“扩展函数”,或者换句话说,Person是一个 * 接收者 *,所以你不需要任何额外的限定条件(比如it.person.等)来引用Person的成员。你可以简单地通过它们的 * 简单名称 * 来引用它们,比如“firstName“。
这就是为什么apply经常被用来设置对象的属性,或者将更改应用到对象,因为它很方便,不必多次编写it.
另一方面,also的lambda参数有Person作为参数,所以要引用它的成员,需要it.xxxit.yyy等。it引用lambda的唯一参数。
这使得also适合于对表达式的结果执行附加操作,因为说“是很自然的,而alsoit“执行此操作。

相关问题