Kotlin中的静态扩展方法

Rag*_*har 125 static-methods kotlin

如何在Kotlin中定义静态扩展方法?这甚至可能吗?我目前有一个扩展方法,如下所示.

public fun Uber.doMagic(context: Context) {
    // ...
}
Run Code Online (Sandbox Code Playgroud)

可以在实例上调用上述扩展名.

uberInstance.doMagic(context) // Instance method
Run Code Online (Sandbox Code Playgroud)

但是如何使它成为静态方法,如下所示.

Uber.doMagic(context)         // Static or class method
Run Code Online (Sandbox Code Playgroud)

And*_*lav 116

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

class Uber {
    companion object {}
}

fun Uber.Companion.doMagic(context: Context) { }
Run Code Online (Sandbox Code Playgroud)

  • 这很好但是如果它是Java类或没有伴侣的类呢? (66认同)
  • 只有**Uber**是*Kotlin*类才有效.有可能静态扩展*Java*类也是很好的 (32认同)
  • @Jire对于这种情况,Kotlin 1.0没有支持 (30认同)
  • 这仍然是不可能的,你可以在这里看到:https://youtrack.jetbrains.com/issue/KT-11968这里有一个相关的SO线程:/sf/ask/2373802021/一个附加静态方法到Java类功能于科特林 (5认同)
  • 我可以看到用默认值扩展JVM框架类(例如String.DEFAULT或Int.DEFAULT)的用例,以防您的域逻辑需要这样做(当前是我的,与空数据类结合使用)。 (2认同)
  • 如果有人在处理 Java 代码时需要一个肮脏的解决方法:/sf/answers/5324377831/ (2认同)

Jus*_*tin 20

由于我在搜索时不断遇到这种情况,因此这里有一种不同的方法,我没有看到任何人提到它以静态方式工作,并且它与泛型一起工作!

技巧是将扩展函数附加到KClass类型的 ,因为它可以静态引用。

正如 @Zaffy 在评论中提到的,扩展特定类型:

fun KClass<MyType>.doSomething() = /* do something */
Run Code Online (Sandbox Code Playgroud)

通用类型扩展:

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

// Extension Property
val <T> KClass<T>.someVal get() = /* something */
Run Code Online (Sandbox Code Playgroud)

用法:

MyType::class.doSomething()

MyType::class.someVal
Run Code Online (Sandbox Code Playgroud)

  • 您可以使用“fun KClass&lt;MyType&gt;.doSomething”来代替。这样就只允许在特定的类上调用它。 (3认同)

luc*_*iel 12

这是官方文件说的:

Kotlin为包级函数生成静态方法.如果您将这些函数注释为@JvmStatic,Kotlin还可以为命名对象或伴随对象中定义的函数生成静态方法.例如:

Kotlin静态方法

class C {
  companion object {
    @JvmStatic fun foo() {}
    fun bar() {}
  }
}
Run Code Online (Sandbox Code Playgroud)

现在,foo()在Java中是静态的,而bar()不是:

C.foo(); // works fine
C.bar(); // error: not a static method
Run Code Online (Sandbox Code Playgroud)

  • 如果 C 是您自己的类,则此方法有效,但您不能像这样扩展其他类,例如,您不能定义 String.foo() 函数。 (3认同)

小智 5

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

class Foo {
    // ...
    companion object {
        public fun bar() {
            // do anything
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

然后你可以这样称呼它:

class Baz {
    // ...
    private fun callBar() {
        Foo.bar()
    }
}
Run Code Online (Sandbox Code Playgroud)


kya*_*y10 5

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

请注意,可以使用可为空的接收器类型定义扩展。即使对象变量的值为null,也可以对其进行扩展。

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

(null as Type?).staticFunction(param1, param2)
Run Code Online (Sandbox Code Playgroud)

因此,我在接收器类型的扩展文件中创建一个值为NULL的val,然后在其他类中使用它来解决此问题。因此,作为示例,这是我如何为NavigationAndroid中的类实现“静态”扩展功能:在我的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) }
}
Run Code Online (Sandbox Code Playgroud)

在使用它的代码中:

SNavigation.createNavigateOnClickListener(R.id.action_gameWonFragment_to_gameFragment)
Run Code Online (Sandbox Code Playgroud)

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

  • 这可能是哈克。而且还聪明又酷。这是对这个问题最有洞察力的回答。Kotlin 正在尽最大努力假装提供一流的扩展,所以在我看来,你可以使用最好的解决方案来处理它的愚蠢之处。好的。 (2认同)