Подтвердить что ты не робот

Статические методы расширения в Котлине

Как вы определяете статический метод расширения в Котлине? Возможно ли это? В настоящее время у меня есть метод расширения, как показано ниже.

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

Вышеупомянутое расширение можно вызвать в экземпляре.

uberInstance.doMagic(context) // Instance method

но как сделать его статическим методом, как показано ниже.

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

Ответ 1

Чтобы достичь Uber.doMagic(context), вы можете написать расширение для объекта-компаньона Uber (требуется объявление объекта сопутствующего объекта):

class Uber {
    companion object {}
}

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

Ответ 2

Вот что говорится в официальной документации:

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

Ответ 3

Вы можете создать статический метод с использованием объекта Companion, например:

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

а затем вы можете вызвать его так:

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

Ответ 4

У меня действительно был этот точный вопрос 30 минут назад, поэтому я начал копаться и не мог найти никакого решения или обходного пути для этого, НО во время поиска я нашел этот раздел на веб-сайте Kotlinglang, в котором говорится:

Обратите внимание, что расширения могут быть определены с обнуляемым типом получателя. Такие расширения могут быть вызваны для переменной объекта, даже если ее значение равно нулю.

Итак, у меня возникла самая безумная идея, почему бы не определить функцию расширения с обнуляемым получателем (без фактического использования этого получателя), а затем вызвать ее для нулевого объекта! Я попробовал это, и это сработало довольно хорошо, но выглядело так безобразно. Это было так:

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

Поэтому я обошел это, создав val в моем файле расширений типа приемника со значением null, а затем использовал его в моем другом классе. Итак, в качестве примера, вот как я реализовал "статическую" функцию расширения для класса Navigation в Android: В моем файле 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 ответят на созданную проблему и добавят эту функцию в язык.

Ответ 5

Рекомендуем вам взглянуть на эту ссылку. Как вы можете видеть, вы просто должны объявить метод на верхнем уровне пакета (файла):

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

Ответ 6

Я также очень люблю иметь возможность добавлять статические методы расширения в Котлин. В качестве обходного пути на данный момент я добавляю метод 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) }