Kotlin 中的静态扩展方法

Static extension methods in Kotlin

如何在 Kotlin 中定义静态扩展方法?这可能吗?我目前有如下所示的扩展方法。

public fun Uber.doMagic(context: Context) {
    // ...
}

可以在实例上调用上述扩展。

uberInstance.doMagic(context) // Instance method

但是我如何使它成为如下所示的静态方法。

Uber.doMagic(context)         // Static or class method

您可以使用 Companion 对象创建静态方法,例如:

class Foo {
    // ...
    companion object {
        public fun bar() {
            // do anything
        }
    }
}

然后你可以这样称呼它:

class Baz {
    // ...
    private fun callBar() {
        Foo.bar()
    }
}

要实现Uber.doMagic(context),可以对Ubercompanion object写一个扩展(需要伴随对象声明):

class Uber {
    companion object {}
}

fun Uber.Companion.doMagic(context: Context) { }

我也非常喜欢在 Kotlin 中添加静态扩展方法的可能性。作为目前的解决方法,我将扩展方法添加到多个 类 而不是在所有这些方法中使用一个静态扩展方法。

class Util    

fun Util.isDeviceOnline(context: Context): Boolean {
    val connMgr = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
    val networkInfo = connMgr.activeNetworkInfo
    return networkInfo != null && networkInfo.isConnected
}

fun Activity.isDeviceOnline(context: Context) = { Util().isDeviceOnline(context) }
fun OkHttpClient.isDeviceOnline(context: Context) = { Util().isDeviceOnline(context) }

官方文档是这样说的:

Kotlin generates static methods for package-level functions. Kotlin can also generate static methods for functions defined in named objects or companion objects if you annotate those functions as @JvmStatic. For example:

Kotlin static methods

class C {
  companion object {
    @JvmStatic fun foo() {}
    fun bar() {}
  }
}

Now, foo() is static in Java, while bar() is not:

C.foo(); // works fine
C.bar(); // error: not a static method

推荐你看看thislink。如您所见,您只需要在包(文件)的 top-level 处声明方法:

package strings
public fun joinToString(...): String { ... }

这等于

package strings;

public class JoinKt {
    public static String joinToString(...) { ... }
}

constans 都是一样的。这个声明

val UNIX_LINE_SEPARATOR = "\n"

等于

public static final String UNIX_LINE_SEPARATOR = "\n";

实际上我在 30 分钟前就有了这个确切的问题,所以我开始四处寻找并找不到任何解决方案或解决方法,但是在搜索时我在 Kotlinglang 网站上发现 this section 指出:

Note that extensions can be defined with a nullable receiver type. Such extensions can be called on an object variable even if its value is null.

然后我有了一个有史以来最疯狂的想法,为什么不定义一个带有可空接收器的扩展函数(而不实际使用该接收器),然后在空对象上调用它! 所以我试了一下,效果很好,但看起来很丑。是这样的:

(null as Type?).staticFunction(param1, param2)

所以我通过在我的接收器类型的扩展文件中创建一个值为 null 的 val 然后在我的另一个 class 中使用它来解决这个问题。 因此,作为示例,下面是我如何为 Android 中的 Navigation class 实现 "static" 扩展函数: 在我的 NavigationExtensions.kt 文件中:

val SNavigation: Navigation? = null
fun Navigation?.createNavigateOnClickListener(@IdRes resId: Int, args: Bundle? = null, navOptions: NavOptions? = null,
                                                navigationExtras: Navigator.Extras? = null) : (View) -> Unit {
    //This is just implementation details, don't worry too much about them, just focus on the Navigation? part in the method declaration
    return { view: View -> view.navigate(resId, args, navOptions, navigationExtras) }
}

在使用它的代码中:

SNavigation.createNavigateOnClickListener(R.id.action_gameWonFragment_to_gameFragment)

显然,这不是一个 class 名称,它只是一个具有空值的 class 类型的变量。这在扩展制造商方面(因为他们必须创建变量)和开发人员方面(因为他们必须使用 SType 格式而不是实际的 class 名称)显然是丑陋的,但它与实际静态函数相比,是目前可以实现的最接近的。希望 Kotlin 语言的开发者能够响应所创建的 issue 并在语言中添加该功能。

要在 kotlin 中创建扩展方法,您必须创建一个 kotlin 文件(不是 class),然后在该文件中声明您的方法 例如:

public fun String.toLowercase(){
    // **this** is the string object
}

在您正在处理的 class 或文件中导入函数并使用它。

由于我在搜索时不断遇到这个问题,这里有一个不同的方法,我还没有看到任何人提到它以静态方式工作并且它适用于泛型!

扩展定义:

// Extension function
fun <T> KClass<T>.doSomething() = /* do something */

// Extension Property
val <T> KClass<T>.someVal get() = /* something */

用法:

MyType::class.doSomething()

MyType::class.someVal

如您所见,诀窍是将扩展函数附加到类型的 KClass,因为它可以被静态引用。

我还需要使用静态方法扩展 Java 对象的能力,发现对我来说最好的解决方案是创建一个扩展 Java class 和在那里添加我的方法。

object Colour: Color(){
    fun parseColor(r: Int?, g: Int?, b: Int?) = parseColor(String.format("#%02x%02x%02x", r, g, b))
}

调用:

val colour = Colour.parseColor(62, 0, 100)