【问题标题】:How to chain lambdas to a resulting lambda in Kotlin?如何将 lambda 链接到 Kotlin 中的结果 lambda?
【发布时间】:2021-10-04 00:06:01
【问题描述】:

...或等同于java.util.Function.andThen()

在 Java 中

Function<String, String> add1 = string -> string + "1";
Function<String, String> add2 = string -> string + "2";
Function<String, Strint> add12 = add1.andThen(add2);

add12.apply("") 返回"12"

我将如何用 Kotlin 编写它?

val add1 = { string:String -> string + "1" }
val add2 = { string:String -> string + "2" }
val add12 = ?

【问题讨论】:

    标签: kotlin lambda chaining


    【解决方案1】:

    您正在寻找的功能称为函数组合。据我所知,它并没有内置在 Kotlin 中(希望对此进行更正)。但是写成扩展函数很容易。

    infix fun<A, B, C> ((B) -> C).compose(that: (A) -> B): (A) -> C =
      { this(that(it)) }
    

    现在我们可以写了

    val add1 = { string:String -> string + "1" }
    val add2 = { string:String -> string + "2" }
    
    println((add2 compose add1)("3")) // Prints "312"
    

    我写compose 使用从右到左的组合,更符合数学函数的工作方式。

    【讨论】:

    • 那么你的意思是 Kotlin 没有对此的原生支持?真可惜。
    • 这已经 5 年了,但看起来 Kotlin 标准库的原始理念是它过于特定于某些编程风格而无法包含:discuss.kotlinlang.org/t/…
    • 这是一个哭泣的耻辱。我已经看到在几种编程语言中提出的论点(Lisp 编码员,在所有人中,似乎认为函数组合不够重要,不能包含在内)。如果你问我,它应该是每种语言的主要内容。
    • 我个人一点都不会错过它,但省略它似乎有点奇怪,因为它是如此微不足道,但他们却非常具体地展示了折叠收藏品的各种变化方式。跨度>
    • 这可能是因为我们在 Kotlin 中没有过多地传递函数引用。这感觉不自然,至少对我来说。 doSomething { add2(add1(it)) }doSomething(::add2 compose ::add1) 更短,更易读,操作顺序也非常清晰。但也许我错过了 lambda 不够用的好例子。
    【解决方案2】:

    当然,这不是您正在寻找的,因为您不能以这种方式将组合函数存储在变量中,但是如果函数本身不存在,您可以使用 run 链接函数的结果将参数作为接收器:

    fun print(string: String) {
        println(add1(string).run(add2))
    }
    
    // or
    
    fun print(string: String) {
        println(string.run(add1).run(add2))
    }
    

    由于run 是一个内联函数,它不会在每个函数周围添加包装对象。

    let 函数将具有完全相同的效果。这是因为当您将 lambda 以外的其他内容传递给高阶函数时,第一个参数是否是接收器并不重要。它们被视为相同的签名。

    【讨论】:

    • 你没有回答我的问题,但也许我不清楚,会更新。
    • 不,我知道我不是第一句话中提到的。只是提供一个可能可行的替代方案,具体取决于您最初希望组合函数的原因。对于搜索并找到此问题并且只想链接一些函数而无需将组合函数存储在变量中的人可能会有所帮助。
    【解决方案3】:

    如果您非常熟悉 Java 函数和/或想要使用它们,您仍然可以这样做(使用 java.util.function.Function):

    val add1 : Function<String, String> = Function { "${it}1"}
    val add2 : Function<String, String> = Function { "${it}2"}
    val add12: Function<String, String> = add1.andThen(add2)
    

    如果我想在 Kotlin 中使用类似的东西,我可能会选择 Tenfour04 也显示的内容,即使用 letrun

    val add1 : (String) -> String = { "${it}1"}
    val add2 : (String) -> String = { "${it}2"}
    val add12 : (String) -> String = { it.let(add1).let(add2) } // or: { add1(it).let(add2) }
    

    如果你比较两者,你只会留下一些东西,如果你省略类型,但它仍然足够清楚组成了什么。

    当然,您可以实现自己的composeandThen 函数。但是,如果您不介意使用额外的库,您可能会对 Arrow 感兴趣,其中已经支持许多功能用例。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-11-28
      • 2020-06-18
      • 1970-01-01
      • 1970-01-01
      • 2018-06-25
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多