从上下文得知接收者时,缩短了对类方法的引用

Ine*_*ego 5 type-inference kotlin method-reference

在以下代码中,

class IncWrapper<T> (val wrapped: T, val base: Int) {
    fun incFunction(increment: Int, func: T.(Int) -> Int): Int {
        return increment + wrapped.func(base)
    }
}

class ClassWithIndecentlyLongName {
    fun square(x: Int) = x * x
}

fun main() {
    val wrapper = IncWrapper(ClassWithIndecentlyLongName(), 2)
    val computed = wrapper.incFunction(1, ClassWithIndecentlyLongName::square)
    println(computed)
}
Run Code Online (Sandbox Code Playgroud)

我们传递了对包装类方法的引用ClassWithIndecentlyLongName。由于在调用站点上知道此类应作为方法的接收者,因此再次传递该类的名称似乎很尴尬/多余。我希望有些事情::square能奏效,但事实并非如此。如果缺少此功能,可能是什么原因?

(这个问题源于试图重构一些冗长的Java代码,将一类的许多字段转换为另一类的代码。)

Rol*_*and 5

使用just ::square意味着它是包或从中调用文件/类的一部分。但这是不正确的。

如果您有这么长的名称,则可以从函数引用切换到实际的lambda,例如:

wrapper.incFunction(1) { square(it) }
Run Code Online (Sandbox Code Playgroud)

如果您有更多参数,则键入别名可能会更有用,例如

typealias Functions = ClassWithIndecentlyLongName // choose a name that's more appropriate

// and calling it as follows:
wrapper.incFunction(1, Functions::square)
Run Code Online (Sandbox Code Playgroud)

或者使用别名导入该类,例如:

import ClassWithIndecentlyLongName as ShortName
Run Code Online (Sandbox Code Playgroud)

但是,更好的方法可能是只丢弃不雅的长名称,而改用更合适的名称。

最后,如果您确实只想使用::square,但仍然可以这样做,只要您提供所需的包装函数,例如:

fun square(c : ClassWithIndecentlyLongName, i : Int) = c.square(i)

// calling it, now works as you wanted:
wrapper.incFunction(1, ::square)
Run Code Online (Sandbox Code Playgroud)

现在:为什么会这样呢?我只能猜。但是对我来说有意义的是,您需要确切指定可以在何处找到该函数。我认为,如果您永远不能确定哪个函数恰好在指定的函数后面,那么它将使代码复杂化。