【问题标题】:What is the advantage of using extension functions as function parameters?使用扩展函数作为函数参数有什么好处?
【发布时间】:2022-12-17 20:39:45
【问题描述】:

我最近仔细研究了 Kotlin 的作用域函数,发现有时他们期望将扩展函数作为参数。就拿申请举个例子:

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
}

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

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

所以我想知道我在这里错过了什么?在高阶函数中使用扩展函数时,Kotlin 中是否存在模式或最佳实践?具体有哪些好处?

【问题讨论】:

    标签: kotlin


    【解决方案1】:

    从消费者的角度来看,两者之间似乎没有太大区别,我可以用相同的方式称呼它们

    这是因为您没有在此处利用接收器或参数。您正在使用现有变量 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 的高阶函数将向函数的调用者提供不同的值。在块内,如果是接收者,参数将作为this可用,否则作为参数。

    【讨论】:

      【解决方案2】:

      Logger.info的情况下,他们确实相差不大。 info 返回Unit,所以TUnitUnit 是一个相当糟糕的例子。

      考虑一个更好的例子:

      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执行此操作”。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2016-09-25
        • 2019-10-12
        • 1970-01-01
        • 2012-05-22
        • 2010-12-04
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多