← Назад к вопросам

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

1.6 Junior🔥 201 комментариев
#Kotlin основы

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI26 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Что такое функция расширения (Extension Function)?

Функция расширения — это один из самых мощных и элегантных инструментов в Kotlin. Она позволяет добавлять новые функции к существующим классам без наследования и без изменения исходного кода. Это ключевая особенность Kotlin, которая делает код более чистым и читаемым.

Базовый синтаксис

Синтаксис: fun ИмяКласса.имяФункции() { ... }

// Добавляем функцию к классу String
fun String.isValidEmail(): Boolean {
    return this.contains("@") && this.contains(".")
}

// Использование:
val email = "user@example.com"
if (email.isValidEmail()) {
    println("Valid email")
}

Как это работает?

Receiver Object — объект, на котором вызывается функция:

fun String.addPrefix(prefix: String): String {
    // this — это receiver object (объект String)
    return prefix + this
}

val result = "World".addPrefix("Hello ") // "Hello World"

Функция расширения — это статическая функция с первым параметром:

// Kotlin код:
fun String.uppercase() = this.toUpperCase()

// Компилируется в (Java bytecode):
public static String uppercase(String $receiver) {
    return $receiver.toUpperCase();
}

Примеры функций расширения

Для String:

fun String.isNumeric(): Boolean {
    return this.all { it.isDigit() }
}

fun String.capitalizeFirstLetter(): String {
    return if (this.isEmpty()) this else this[0].uppercase() + this.substring(1)
}

val str = "android"
println(str.isNumeric()) // false
println(str.capitalizeFirstLetter()) // "Android"

Для Collections:

fun <T> List<T>.secondOrNull(): T? {
    return if (this.size > 1) this[1] else null
}

fun <T> List<T>.filterNotNull(): List<T> {
    return this.filter { it != null }
}

val list = listOf(1, 2, 3, null)
println(list.secondOrNull()) // 2

Для View (Android):

fun View.show() {
    this.visibility = View.VISIBLE
}

fun View.hide() {
    this.visibility = View.GONE
}

fun View.setClickListener(action: () -> Unit) {
    this.setOnClickListener { action() }
}

// Использование:
button.show()
button.setClickListener { 
    Log.d("Button", "Clicked")
}

Extension Properties — свойства расширения

Можно добавлять не только функции, но и свойства:

val String.firstCharacter: Char?
    get() = this.firstOrNull()

val <T> List<T>.middle: T?
    get() = if (this.size > 0) this[this.size / 2] else null

val str = "Kotlin"
println(str.firstCharacter) // K

val list = listOf(1, 2, 3, 4, 5)
println(list.middle) // 3

Инфиксные функции расширения

Можно создавать функции расширения в инфиксной нотации:

infix fun String.repeat(times: Int): String {
    return this.repeat(times)
}

val result = "Ha" repeat 3 // "HaHaHa"

infix fun <T> List<T>.join(other: List<T>): List<T> {
    return this + other
}

val merged = listOf(1, 2) join listOf(3, 4) // [1, 2, 3, 4]

Область видимости

Локальные функции расширения:

fun processData(data: String) {
    // Видна только внутри этой функции
    fun String.isPalindrome(): Boolean {
        return this == this.reversed()
    }
    
    println(data.isPalindrome())
}

На уровне файла:

// StringUtils.kt
fun String.toTitleCase(): String {
    return this.split(" ").joinToString(" ") { 
        it.capitalizeFirstLetter() 
    }
}

// Видна везде после импорта
// import com.example.toTitleCase

Функции расширения на null

fun String?.isNullOrBlank(): Boolean {
    return this == null || this.isBlank()
}

val nullable: String? = null
println(nullable.isNullOrBlank()) // true

Практические примеры для Android

Работа с SharedPreferences:

fun SharedPreferences.putString(key: String, value: String) {
    this.edit().putString(key, value).apply()
}

sharedPref.putString("user_name", "John")

Работа с Context:

fun Context.showToast(message: String) {
    Toast.makeText(this, message, Toast.LENGTH_SHORT).show()
}

context.showToast("Hello, Android!")

DP в пиксели:

fun Int.dpToPx(context: Context): Int {
    return (this * context.resources.displayMetrics.density).toInt()
}

val margin = 16.dpToPx(context)

Приоритет разрешения

Если существует оригинальная функция и функция расширения с одинаковым названием — оригинальная функция имеет приоритет:

fun String.length(): Int = 999 // функция расширения

println("Hello".length()) // 5 (оригинальное свойство)

Преимущества и недостатки

Преимущества:

  • Читаемый и интуитивный код
  • Избегаем наследования и wrapper классов
  • Работает с final классами
  • Типобезопасность
  • Работает как методы класса (IDE помогает с автодополнением)

Недостатки:

  • Только доступ к публичному API
  • Нельзя добавить новое состояние
  • Нельзя переопределить функцию расширения (как виртуальный метод)

Функции расширения — фундаментальная часть Kotlin-way разработки, которая делает код более выразительным и удобным для чтения.