web-dev-qa-db-ja.com

Kotlinの静的拡張メソッド

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

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

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

uberInstance.doMagic(context) // Instance method

しかし、次のように静的メソッドにするにはどうすればよいですか?.

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

Uber.doMagic(context)を実現するには、 コンパニオンオブジェクト of Uberに拡張機能を記述できます(コンパニオンオブジェクト宣言が必要です)。

class Uber {
    companion object {}
}

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

これは公式文書に書かれていることです:

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
9
lucasddaniel

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

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

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

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

30分前に実際にこの正確な質問があったので、探し始めましたが、解決策も回避策も見つかりませんでしたが、検索中に このセクション がKotlinglang Webサイトで次のように記載されています:

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

だから、私はこれまでで最もクレイジーなアイデアを持っていました。なぜヌル機能可能なレシーバーで拡張機能を定義し(実際にそのレシーバーを使用せずに)、それをヌルオブジェクトで呼び出すのですか!だから私はそれを試してみたが、それはかなりうまくいったが、それはとてもく見えた。次のようなものでした:

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

そのため、nullの値を持つレシーバー型の拡張機能ファイルにvalを作成し、それを他のクラスで使用することでそれを回避しました。そのため、例として、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)

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

1
kyay

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