Можно ли вызывать функции расширения "статическим" способом?
Можно ли создать функцию расширения и вызывать ее, как если бы она была статической?
Например...
fun System.sayByeAndExit() {
println("Goodbye!")
System.exit()
}
fun main(args: Array<String>) {
System.sayByeAndExit() // I'd like to be able to call this
}
Я знаю, что пример кода не работает...
Я понимаю, что функции расширения kotlin разрешаются статически, как упомянуто в Справочнике Kotlin (Функции расширения), но это не означает, что их можно вызывать так, как если бы они были статическими функциями внутри класса (в смысле Java).
Я также понимаю, что этот код не будет работать, потому что нет экземпляра System для передачи в метод, который сгенерирует компилятор; поэтому он не скомпилируется.
Зачем мне это?
Некоторым из вас может быть интересно, почему это поведение желательно. Я могу понять, почему вы думаете, что это не так, вот несколько причин:
- Он обладает всеми преимуществами, которые дают стандартные функции расширения.
- Экземпляр класса не нужно создавать просто для доступа к дополнительным функциям.
- Доступ к функциям можно получить из общесистемного контекста (при условии, что класс видим).
Чтобы подвести итог...
Есть ли у Kotlin способ "зацепить" статическую функцию в классе? Я хотел бы знать.
2 ответа
Вы действительно запрашиваете "функции расширения для ссылки на класс" или "добавление статических методов к существующим классам", что было затронуто здесь другим вопросом: как можно добавить статические методы к классам Java в Kotlin, который покрывается запросом функции KT- 11968
Функции расширения не могут быть добавлены ни к чему, что не имеет экземпляра. Ссылка на класс не является экземпляром, и поэтому вы не можете расширить что-то вроде java.lang.System
, Однако вы можете расширить сопутствующий объект существующего класса. Например:
class LibraryThing {
companion object { /* ... */ }
}
Позволяет продлить LibraryThing.Companion
и, следовательно, называя некоторые новые myExtension()
Метод будет выглядеть так, как будто вы расширяете саму ссылку на класс, тогда как на самом деле вы расширяете одноэлементный экземпляр объекта-компаньона:
fun LibraryThing.Companion.myExtension() = "foo"
LibraryThing.Companion.myExtension() // results in "foo"
LibraryThing.myExtension() // results in "foo"
Поэтому вы можете найти, что некоторые библиотеки Kotlin добавляют пустые сопутствующие объекты только для этого случая. Другие нет, а для тех, кому "не повезло". Поскольку в Java нет сопутствующих объектов, вы не можете сделать то же самое для Java.
Другая обычно запрашиваемая функция - взять существующий статический метод Java, который принимает экземпляр класса в качестве первого параметра, и заставить его вести себя как функция расширения. Это отслеживается проблемами KT-5261, KT-2844, KT-732, KT-3487 и, возможно, другими запросами функций.
Вы можете определить функцию расширения для object
и использовать его из общесистемного контекста. Объект будет создан только один раз.
object MyClz
fun MyClz.exit() = System.exit(0)
fun main(args: Array<String>) {
MyClz.exit()
}
Или же
class MyClz {
companion object
}
fun MyClz.Companion.exit() = System.exit(0)
fun main(args: Array<String>) {
MyClz.exit()
}