Расширения областей видимости и companion-расширения
Ограничивайте видимость расширений и добавляйте расширения к companion object.
«Расширения областей видимости и companion-расширения» — бесплатный урок Kotlin Academy на CoddyKit. Это урок 3 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения Kotlin Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс Kotlin Academy содержит 4 уроков всего.
Зачем нужны расширения с областью действия
По умолчанию расширения видны везде, где они импортированы. Ограничение области действия сужает видимость до класса, файла или контекста, уменьшая загрязнение пространства имён и упрощая поиск нужного расширения.
Расширения, закрытые на уровне файла
Пометьте функцию-расширение как private на уровне файла, чтобы сделать её доступной только в этом файле.
private fun String.shout() = uppercase() + "!"
fun main() {
println("hello".shout()) // HELLO!
}Внутренняя видимость
Используйте internal, чтобы ограничить расширения текущим модулем — это удобно для внутренней реализации библиотеки, не предназначенной для внешнего использования.
internal fun List<Int>.sumIfPositive(): Int = filter { it > 0 }.sum()
fun main() {
println(listOf(-1, 2, 3, -4).sumIfPositive()) // 5
}Функции-расширения, являющиеся членами
Объявите расширение внутри класса, чтобы им можно было пользоваться только при наличии экземпляра этого класса в текущей области действия. У него два получателя: диспетчеризации (класс) и расширения (целевой объект).
class StringHelper(val prefix: String) {
fun String.withPrefix() = prefix + this
fun build(): String = "world".withPrefix() // calls extension via instance
}
fun main() {
println(StringHelper("hello ").build()) // hello world
}Видимость расширений-членов
Расширения-члены недоступны за пределами класса диспетчеризации. Это полезно для инкапсуляции.
class Repo {
fun List<Int>.allPositive() = all { it > 0 }
fun check(xs: List<Int>) = xs.allPositive()
}
fun main() {
val r = Repo()
println(r.check(listOf(1, 2, 3))) // true
// listOf(1).allPositive() // ERROR — no access
}Расширение сопутствующего объекта
Добавьте расширение к сопутствующему объекту класса. Для вызывающего кода оно выглядит как статический метод, но находится за пределами класса.
class Greeter {
companion object
}
fun Greeter.Companion.morning() = "Good morning!"
fun main() {
println(Greeter.morning())
}Зачем нужны расширения сопутствующих объектов
Они полезны для добавления фабричных методов или вспомогательных функций за пределами исходного класса — без его изменения.
class User(val name: String) {
companion object
}
fun User.Companion.guest() = User("Guest")
fun User.Companion.system() = User("System")
fun main() {
println(User.guest().name)
println(User.system().name)
}Необходим пустой сопутствующий объект
Класс должен объявить сопутствующий объект (даже пустой), чтобы к нему можно было присоединить расширения. В противном случае цель расширения не существует.
class Box {
companion object // required, even if empty
}
fun Box.Companion.create(): Box = Box()
fun main() {
println(Box.create())
}Расширения с ограниченной областью действия через импорты
Можно ограничить использование расширения, импортируя его только в определённых файлах. Файлы, в которых оно не импортировано, не смогут его видеть.
// File A:
// fun String.shout() = uppercase()
// File B imports:
// import com.example.shout
// Only File B can call shout()
fun String.shout() = uppercase() + "!"
fun main() { println("hi".shout()) }Функция-расширение через функцию области действия
Используйте with или apply, чтобы временно добавить объект в область действия для использования расширения.
class StringTools {
fun String.greet() = "Hello, $this!"
fun process(name: String) = with(this) {
name.greet()
}
}
fun main() {
println(StringTools().process("Ada"))
}Свойства-расширения у объекта-компаньона
Расширениями объекта-компаньона могут быть и свойства — добавляйте именованные константы за пределами класса.
class HttpStatus {
companion object
}
val HttpStatus.Companion.OK_CODE: Int get() = 200
val HttpStatus.Companion.NOT_FOUND: Int get() = 404
fun main() {
println(HttpStatus.OK_CODE)
println(HttpStatus.NOT_FOUND)
}Рекомендации
Используйте private для вспомогательных средств, доступных только в файле, internal — для API, доступного только в модуле, расширения-члены — для инкапсуляции, а расширения объекта-компаньона — для добавления вспомогательных средств, похожих на фабричные, за пределами класса.
class StringUtils {
companion object
}
fun StringUtils.Companion.isAlpha(s: String) = s.all { it.isLetter() }
fun main() {
println(StringUtils.isAlpha("hello"))
println(StringUtils.isAlpha("hi5"))
}Быстрая проверка
Что должно быть в классе, чтобы за его пределами можно было добавить к нему расширение объекта-компаньона?
Повторение
Ограничивайте область видимости расширений с помощью private, internal или создавайте их как расширения-члены внутри класса. Добавляйте расширения объекта-компаньона (функции или свойства) за пределами класса, присоединяя их к объявленному объекту-компаньону этого класса. Это уменьшает загрязнение пространства имён и сохраняет модульность кода.
Изучай Kotlin с ИИ-репетитором — бесплатно
Пиши и запускай код прямо в браузере, получай мгновенную помощь от ИИ-репетитора 24/7 и продолжи учиться на сайте или в приложении.
- Курсы
- 51
- Уроки
- 203
Часто задаваемые вопросы
Урок «Расширения областей видимости и companion-расширения» бесплатный?
Да — полный текст урока «Расширения областей видимости и companion-расширения» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс Kotlin Academy, подпишись на CoddyKit PRO. Курс Kotlin Academy содержит 4 уроков всего.
Чему я научусь в уроке «Расширения областей видимости и companion-расширения»?
Ограничивайте видимость расширений и добавляйте расширения к companion object. Ты практикуешь Kotlin Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.
Нужен ли мне опыт, чтобы начать Kotlin Academy?
Предыдущий опыт не требуется. Kotlin Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 3 из 4.
Сколько времени занимает урок «Расширения областей видимости и companion-расширения»?
Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.
Можно ли писать и запускать код в этом уроке Kotlin Academy?
Да. Каждый урок Kotlin Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.
Все уроки этого курса
- Функции-расширения: синтаксис и правила диспетчеризации
- Свойства-расширения и вычисляемые расширения
- Расширения областей видимости и companion-расширения
- Практические расширения: помощники для Context, View и String