0Pricing
Kotlin Academy · Урок

Функции-расширения: синтаксис и правила диспетчеризации

Пишите функции-расширения и разбирайтесь в семантике статической диспетчеризации.

«Функции-расширения: синтаксис и правила диспетчеризации» — бесплатный урок Kotlin Academy на CoddyKit. Это урок 1 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения Kotlin Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс Kotlin Academy содержит 4 уроков всего.

Что такое функции-расширения

Функции-расширения позволяют добавлять новые функции к существующим классам без их изменения и без использования наследования.

Базовый синтаксис функции-расширения

Укажите перед именем функции тип, который Вы расширяете; он называется типом-получателем.
fun String.shout(): String = uppercase() + "!"
println("hello".shout())  // HELLO!
fun Int.isEven() = this % 2 == 0
println(4.isEven())  // true

this в расширениях

Внутри функции-расширения this обозначает объект-получатель.
fun List<Int>.secondOrNull(): Int? {
    return if (size >= 2) this[1] else null
}
println(listOf(10, 20, 30).secondOrNull())  // 20
println(listOf(5).secondOrNull())           // null

Статическая диспетчеризация: расширения не переопределяются

Функции-расширения разрешаются статически во время компиляции на основе объявленного типа — они НЕ являются виртуальными.
open class Base
class Child : Base()
fun Base.greet() = "Hello from Base"
fun Child.greet() = "Hello from Child"

val obj: Base = Child()
println(obj.greet())  // "Hello from Base" (static dispatch!)

Расширения и функции-члены

Если в классе есть функция-член с такой же сигнатурой, как у функции-расширения, всегда вызывается функция-член.
class Greeter {
    fun hello() = "member hello"
}
fun Greeter.hello() = "extension hello"  // shadowed!
println(Greeter().hello())  // "member hello"

Расширения для допускающего null получателя

Можно расширять типы, допускающие значение null. Внутри обрабатывайте null с помощью проверок вида this == null.
fun String?.orEmpty() = this ?: ""
fun Any?.toStringSafe() = this?.toString() ?: "null"
println(null.orEmpty())  // ""
println(42.toStringSafe())  // "42"

Видимость и область действия

Расширения могут быть верхнеуровневыми (глобальными), находиться в классе (расширения-члены) или в файле. Для них действуют обычные правила видимости.
// Top-level extension:
fun List<String>.joinUppercase() = joinToString { it.uppercase() }
// Private to file:
private fun String.clean() = trim().lowercase()

Расширения сопутствующего объекта

Добавляйте расширения к сопутствующему объекту, чтобы расширить пространство имён уровня класса.
class User(val name: String) {
    companion object
}
fun User.Companion.guest() = User("Guest")
val guest = User.guest()

Расширения типов стандартной библиотеки

Расширяйте любой тип, включая встроенные типы.
fun Double.roundTo(decimals: Int): Double {
    val factor = Math.pow(10.0, decimals.toDouble())
    return Math.round(this * factor) / factor
}
println(3.14159.roundTo(2))  // 3.14

Организация расширений

Группируйте расширения для одного типа в отдельном файле, например StringExtensions.kt или DateExtensions.kt.
// StringExtensions.kt
fun String.titleCase() = split(" ")
    .joinToString(" ") {
        it.replaceFirstChar { c -> c.uppercase() }
    }
println("hello world".titleCase())  // Hello World

Расширения не имеют доступа к закрытым членам

Расширения имеют доступ только к открытым и внутренним членам — но не к закрытым или защищённым.
class Secret {
    private val key = "hidden"
    val name = "public"
}
fun Secret.reveal() {
    println(name)  // OK
    // println(key)  // Error: key is private
}

Быстрая проверка

Если функция-член класса и функция-расширение имеют одинаковую сигнатуру, какая из них вызывается?

Итоги

Функции-расширения добавляют поведение любому классу без его изменения. Они вызываются статически, без переопределения. Члены имеют приоритет над расширениями. Используйте получатели, допускающие null, для безопасных помощников. Далее: свойства-расширения!

Часто задаваемые вопросы

Урок «Функции-расширения: синтаксис и правила диспетчеризации» бесплатный?

Да — полный текст урока «Функции-расширения: синтаксис и правила диспетчеризации» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс Kotlin Academy, подпишись на CoddyKit PRO. Курс Kotlin Academy содержит 4 уроков всего.

Чему я научусь в уроке «Функции-расширения: синтаксис и правила диспетчеризации»?

Пишите функции-расширения и разбирайтесь в семантике статической диспетчеризации. Ты практикуешь Kotlin Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.

Нужен ли мне опыт, чтобы начать Kotlin Academy?

Предыдущий опыт не требуется. Kotlin Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 1 из 4.

Сколько времени занимает урок «Функции-расширения: синтаксис и правила диспетчеризации»?

Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.

Можно ли писать и запускать код в этом уроке Kotlin Academy?

Да. Каждый урок Kotlin Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.

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

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