Kotlin Academy · Урок

Расширения областей видимости и companion-расширения

Ограничивайте видимость расширений и добавляйте расширения к companion object.

Урок 3 из 414 шагов

«Расширения областей видимости и 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 — локальная установка не требуется.

Все уроки этого курса

  1. Функции-расширения: синтаксис и правила диспетчеризации
  2. Свойства-расширения и вычисляемые расширения
  3. Расширения областей видимости и companion-расширения
  4. Практические расширения: помощники для Context, View и String
← Назад к Kotlin Academy