如何从lambda引用外部函数?

时间:2018-09-02 15:01:43

标签: kotlin

问题在评论中。我想引用外部函数append,而不是StringBuilder中定义的外部函数,我该怎么做?

fun append(c: Char) {
    println("TEST")
}

fun sbTest() = with(StringBuilder()) {
    for(c in 'A'..'Z') {
        append(c) // how do I refer to the append function declared above?
    }
    toString()
}

我知道我可以引入一个函数引用变量,如下所示:

val f = ::append

并调用f而不是append,但是还有另一种方法吗?

2 个答案:

答案 0 :(得分:5)

问题在于,with内的任何调用都遮盖了外部函数,因为引入了this。如果您有一个类和一个具有相同签名的函数的顶级函数,则会出现相同的问题。

显而易见的选择就是重新命名。而且,您所拥有的功能与其实际功能相比并没有真正的描述性。但是,如果由于某种原因而无法重命名,则还有其他选择。

对于com.some.package.method之类的实例,Kotlin中的包可以引用顶级方法。也可以将其原样导入,这是最常用的方法。很少有被称为com.some.package.method()的方法。

Kotlin与Python一样,允许as导入。也就是说,您可以执行以下操作:

package com.example;

// This is the important line; it declares the import with a custom name.
import com.example.append as appendChar; // Just an example name; this could be anything ***except append***. If it's append, it defeats the purpose

fun append(c: Char) {
    println("TEST")
}

fun sbTest() = with(StringBuilder()) {
    for(c in 'A'..'Z') {
        appendChar(c) 
    }
    toString()
}

或者,正如我提到的,您可以添加软件包:

for(c in 'A'..'Z') {
    com.example.append(c) 
}

val f = ::append当然也是一个选项,无论哪种方式,重命名该函数都比使用as或常量创建导入要容易得多,前提是您有权使用该函数(并且不属于依赖项)。


如果您的文件不在软件包中,我不建议您这样做,则可以将导入声明为:

import append as appendChar

答案 1 :(得分:2)

您也可以使用扩展功能代替with(),例如.let{...}。 这会将StringBuilder作为扩展函数的参数发送为it(您可以将其重命名为您想要的任何东西)

fun sbTest() = StringBuilder().let{ it ->
    for(c in 'A'..'Z') {
        // using string builder
        it.append(c)
        // using your function
        append(c) 
    }
    it.toString()
}

.let{...}函数返回您的最后一条语句,也就是toString()中的字符串,因此您的原始函数仍会正确返回它。其他函数可以返回this,例如.also{...}

我倾向于使用扩展功能而不是with(),因为它们更灵活。

请参阅此文章以掌握扩展功能:https://medium.com/@elye.project/mastering-kotlin-standard-functions-run-with-let-also-and-apply-9cd334b0ef84

编辑:混合了also{}let{}。我换了