Kotlin中的静态扩展方法

4szc88ey  于 2023-04-12  发布在  Kotlin
关注(0)|答案(9)|浏览(154)

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

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

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

uberInstance.doMagic(context) // Instance method

但是我怎么把它变成静态方法呢,如下所示。

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

uqxowvwt1#

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

class Uber {
    companion object {}
}

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

zsbz8rwp2#

这是官方文件所说的:
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
tktrz96b

tktrz96b3#

实际上,我在30分钟前就有了这个问题,所以我开始四处挖掘,找不到任何解决方案或变通方法,但在搜索时,我在Kotlinglang网站上找到了这个部分,其中指出:
注意,扩展可以用一个可空的接收器类型来定义。这样的扩展可以在一个对象变量上调用,即使它的值为空。
于是我有了一个最疯狂的想法,为什么不定义一个带有可空接收器的扩展函数(实际上不使用那个接收器),然后在一个空对象上调用它呢!于是我尝试了一下,效果很好,但是看起来很难看。它是这样的:

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

所以我绕过了这个问题,在接收器类型的扩展文件中创建了一个瓦尔,它的值为null,然后在我的另一个类中使用它。所以,作为一个例子,下面是我如何在Android中为Navigation类实现一个“静态”扩展函数:在我的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语言的开发者会对创建的issue做出响应,并在语言中添加该功能。

du7egjpx

du7egjpx4#

由于我在搜索时不断遇到这种情况,这里有一种不同的方法,我还没有看到任何人提到它以静态的方式工作 * 并且 * 它可以与泛型一起工作!
技巧是将扩展函数附加到类型的KClass,因为它可以静态引用。
正如@Zaffy在评论中提到的,要扩展特定类型:

fun KClass<MyType>.doSomething() = /* do something */

泛型类型扩展:

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

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

使用方法:

MyType::class.doSomething()

MyType::class.someVal
4ngedf3f

4ngedf3f5#

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

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

然后你可以这样称呼它:

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

dl5txlt96#

推荐你看一下this链接。正如你所看到的,你只需要在包的顶层(文件)声明方法:

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

这等于

package strings;

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

和康斯坦斯在一起,一切都是一样的。这个宣言

val UNIX_LINE_SEPARATOR = "\n"

等于

public static final String UNIX_LINE_SEPARATOR = "\n";
jyztefdp

jyztefdp7#

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

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

vmdwslir8#

我也很喜欢在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) }
pgx2nnw8

pgx2nnw89#

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

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

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

相关问题