Kotlin中的静态扩展方法


142

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

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

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

uberInstance.doMagic(context) // Instance method

但是我如何使其变为静态方法,如下所示。

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

1
“静态扩展方法”是什么意思?
安德烈·布雷斯拉夫

3
我可以在没有实例的情况下调用的方法,但它仍然是类的扩展。(常规Java静态方法)
Ragunath Jawahar

我认为这可能不是Kotlin扩展的好用途,我在尝试外推C#概念时也想到了同一件事。但是实际上,用法非常相似。Kotlin扩展虽然声称是静态分派的,但如果有这种情况或延迟绑定到实例,则感觉就像是动态“附加”的。如果我没记错的话...或者也许我完全理解错了:)
2015年

7
当前,您无法编写将在类名而非类实例上调用的扩展方法。的确,扩展功能采用了作为实例的接收器参数,因此无法跳过此部分。另一方面,我们正在努力为类对象编写扩展名,以便您以类名调用它,但是接收者具有类对象的类型
Andrey Breslav 2015年

@AndreyBreslav您可以更新我们是否允许静态扩展功能吗?我也很想念它。
Lars Blumberg 2015年

Answers:


143

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

class Uber {
    companion object {}
}

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

79
很好,但是如果它是Java类或没有伴侣的类怎么办?
吉尔2015年

31
@Jire针对此类情况,Kotlin 1.0中没有任何支持
Andrey Breslav

2
我可以看到用默认值扩展JVM框架类(例如String.DEFAULT或Int.DEFAULT)的用例,以防您的域逻辑需要这样做(当前是我的,与空数据类结合使用)。
Steffen Funke

36
只要UberKotlin班,就可以使用。最好还可以静态扩展Java
kosiara-Bartosz Kosarzycki

6
这仍然是不可能的,因为您可以在这里看到:youtrack.jetbrains.com/issue/KT-11968这里有一个相关的SO线程:stackoverflow.com/questions/33911457/…–
narko

12

官方文件是这样说的:

Kotlin为程序包级功能生成静态方法。如果您将这些功能注释为@JvmStatic,则Kotlin还可以为在命名对象或伴随对象中定义的功能生成静态方法。例如:

Kotlin静态方法

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

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

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

8

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

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

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

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

因此,我在接收器类型的扩展文件中创建一个值为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) }
}

在使用它的代码中:

SNavigation.createNavigateOnClickListener(R.id.action_gameWonFragment_to_gameFragment)

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


2
哈克,这可能是。但也聪明爽。这是对该问题最有见地的回答。Kotlin会竭尽所能,假冒提供一流的扩展,因此IMO,您将使用最佳解决方案来解决其缺陷。真好
特拉维斯·格里格斯

5

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

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

然后您可以这样称呼它:

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

我认为这实际上不是静态的。伴随对象允许您使用类名称进行调用,但仍使用类的实例。另外,问题是关于静态扩展功能,而不仅仅是静态功能。但是,要具有静态功能,可以使用platformStatic注释。
拉古纳斯·贾瓦哈尔(Ragunath Jawahar)

1
platformStaticJvmStatic在当前的Kotlin中被重命名。
杰森·米纳德

0

建议您查看链接。如您所见,您只需要在包(文件)的顶层声明方法:

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

这等于

package strings;

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

对于constan,一切都是相同的。这个宣言

val UNIX_LINE_SEPARATOR = "\n"

等于

public static final String UNIX_LINE_SEPARATOR = "\n";

-3

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

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) }

2
最初的问题是关于如何使用静态方法扩展javaclass 。在您的情况下,这意味着能够在Activity.isDeviceOnline(...)没有实例的情况下直接进行调用Activity
Fabian Zeindl '16

-4

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

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

将函数导入正在使用的类或文件中,然后使用它。


标题甚至都不是问题
daniel.jbatiz
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.