Статические методы расширения в Котлине
Как вы определяете статический метод расширения в Котлине? Возможно ли это? В настоящее время у меня есть метод расширения, как показано ниже.
public fun Uber.doMagic(context: Context) {
// ...
}
Вышеупомянутое расширение можно вызвать в экземпляре.
uberInstance.doMagic(context) // Instance method
но как сделать его статическим методом, как показано ниже.
Uber.doMagic(context) // Static or class method
Ответы
Ответ 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) }