Kotlinの静的拡張メソッド


142

Kotlinで静的拡張メソッドをどのように定義しますか?これは可能ですか?現在、以下のような拡張メソッドがあります。

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

上記の拡張機能はインスタンスで呼び出すことができます。

uberInstance.doMagic(context) // Instance method

しかし、以下のように静的メソッドにする方法を教えてください。

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

1
「静的拡張方式」とはどういう意味ですか?
Andrey Breslav、2015年

3
インスタンスがなくても呼び出すことができるメソッドですが、それでもクラスの拡張です。(通常のJava静的メソッド)
Ragunath Jawahar 2015

Kotlin拡張機能の意図した使用法ではないかもしれないと思うので、C#の概念を推定する際に同じことを考えました。しかし、実際には使用法はかなり似ています。Kotlin拡張機能は、静的にディスパッチされると主張している一方で、そのようなものが存在する場合、またはインスタンスに遅延バインドされている場合、動的に「アタッチ」されているように感じます。私が間違っていない場合...またはおそらくそれを完全に間違っている:)
Dan

7
現在、クラスインスタンスではなくクラス名で呼び出される拡張メソッドを作成することはできません。実際、拡張関数はインスタンスであるレシーバーパラメーターを受け取るため、この部分をスキップする方法はありません。一方、クラスオブジェクトの拡張を作成する方法に取り組んでいるため、クラス名で呼び出しますが、レシーバーはクラスオブジェクトのタイプを持っています
Andrey Breslav

@AndreyBreslav静的拡張関数が許可されるかどうかを更新できますか?私もそれを逃しています。
Lars Blumberg、

回答:


143

達成するためにUber.doMagic(context)あなたがの拡張書くことができ、コンパニオンオブジェクトUber(コンパニオンオブジェクトの宣言が必要です):

class Uber {
    companion object {}
}

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

79
これはいいですが、それがJavaクラスまたはコンパニオンのないクラスの場合はどうでしょうか。
Jire、2015年

31
このような場合の@ Jire、Kotlin 1.0ではサポートはありません
Andrey

2
ドメインロジックで必要な場合に備えて、デフォルト値(String.DEFAULTやInt.DEFAULTなど)でJVMフレームワーククラスを拡張する場合の使用例を見ることができます(現在、私は空のデータクラスと組み合わせて使用​​しています)。
Steffen Funke

36
UberKotlinクラスである場合にのみ機能します。Javaクラスも静的に拡張する可能性があるとよいでしょう
kosiara-Bartosz Kosarzycki

6
:あなたがここに見ることができるので、これは可能ではありませんyoutrack.jetbrains.com/issue/KT-11968:ここでは、関連するSOスレッドがあるstackoverflow.com/questions/33911457/...
NÄRKO

12

これは公式文書が言うことです:

Kotlinは、パッケージレベルの関数の静的メソッドを生成します。Kotlinは、名前付きオブジェクトまたはコンパニオンオブジェクトで定義された関数に静的メソッドを生成することもできます(それらの関数に@JvmStaticとして注釈を付ける場合)。例えば:

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 Webサイトでこのセクションを見つけ、次のように述べています:

拡張機能はnull許容のレシーバータイプで定義できることに注意してください。そのような拡張は、その値がnullであってもオブジェクト変数で呼び出すことができます。

それで私は今までで最もクレイジーなアイデアを持っていました、なぜnull可能なレシーバーで拡張関数を定義し(実際にそのレシーバーを使用せずに)、それからそれを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)

明らかに、これはクラス名ではなく、null値を持つクラス型の変数です。これは明らかに、拡張機能の作成者側(変数を作成する必要があるため)および開発者側(SType実際のクラス名の代わりに形式を使用する必要があるため)では醜いですが、現在達成できる最も近い方法です。実際の静的関数と比較して。うまくいけば、Kotlin言語メーカーが作成された問題に対応し、その機能を言語に追加することを望みます。


2
これはハッキーかもしれません。しかし、また賢いです。これは、質問に対する最も洞察に満ちた回答です。Kotlinは、ファーストクラスの拡張機能を提供するためにできる限り最善を尽くしています。そのため、IMOでは、その最善を尽くすソリューションを使用して、そのイナニティーに対処します。いいね。
Travis Griggs、

5

次のようなCompanionオブジェクトを使用して静的メソッドを作成できます。

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

そして、あなたはそれを次のように呼び出すことができます:

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

私はそれが実際には静的ではないと思います。コンパニオンオブジェクトを使用すると、クラス名を使用して呼び出すことができますが、クラスのインスタンスは引き続き使用されます。また、問題は、静的関数だけでなく、静的拡張関数に関するものでした。ただし、静的関数を使用するには、platformStaticアノテーションを使用できます。
Ragunath Jawahar 2015

1
platformStaticJvmStatic現在のKotlinで名前が変更されました。
Jayson Minard、2015

0

このリンクをご覧になることをお勧めします。ご覧のとおり、パッケージ(ファイル)の最上位でメソッドを宣言するだけです。

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";

-3

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

2
元の質問は、javaclassを静的メソッドで拡張する方法についてでした。あなたの場合、それはActivity.isDeviceOnline(...)のインスタンスがなくても文字通り呼び出すことができることを意味しますActivity
Fabian Zeindl

-4

kotlinで拡張メソッドを作成するには、(クラスではなく)kotlinファイルを作成してから、ファイルでメソッドを宣言する必要があります。例:

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

作業中のクラスまたはファイルに関数をインポートして使用します。


タイトルも問題ではない
daniel.jbatiz
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.