Как объявить и использовать extension-функции?
Extension-функции (расширяющие функции) в Kotlin позволяют добавлять новые функции к уже существующим классам без необходимости изменять их исходный код или использовать наследование. Это особенно удобно при работе с библиотечными классами или для улучшения читаемости и переиспользуемости кода.
Синтаксис объявления
fun <Имя_типа>.<Имя_функции>() { ... }
Ключевой момент: перед именем функции пишется тип, который она будет расширять — это и делает функцию extension.
Пример:
fun String.addBrackets(): String {
return "\[$this\]"
}
Теперь можно вызывать .addBrackets() у любой строки:
val name = "Alex".addBrackets() // \[Alex\]
Как это работает
-
this в теле функции — это ссылка на экземпляр объекта, для которого вызывается расширение.
-
Extension-функции не изменяют сам класс — они синтаксический сахар. Компилятор преобразует вызов в обычный статический вызов с передачей объекта как аргумента.
val name = "Elvis".addBrackets()
// превращается в: ExtensionKt.addBrackets("Elvis")
Примеры
Расширение стандартного типа
fun Int.square(): Int {
return this \* this
}
val result = 5.square() // 25
Расширение nullable-типа
fun String?.orAnonymous(): String {
return this ?: "Anonymous"
}
val userName: String? = null
println(userName.orAnonymous()) // Anonymous
Использование с классами
class Person(val name: String)
fun Person.sayHello() {
println("Привет, меня зовут $name")
}
val p = Person("Иван")
p.sayHello() // Привет, меня зовут Иван
Организация и импорт
Extension-функции можно определять в любом файле, и потом импортировать:
// File: utils/StringUtils.kt
fun String.trimAndCapitalize(): String {
return this.trim().replaceFirstChar { it.uppercase() }
}
Использование:
import utils.trimAndCapitalize
val s = " hello"
println(s.trimAndCapitalize()) // Hello
Extension-функции для коллекций
fun List<Int>.sumOfSquares(): Int {
return this.map { it \* it }.sum()
}
val numbers = listOf(1, 2, 3)
println(numbers.sumOfSquares()) // 14
Extension-функции в классе
Можно объявлять расширения внутри классов:
class Logger {
fun String.log() {
println("LOG: $this")
}
fun doSomething() {
"Hello".log()
}
}
Такие расширения видны только внутри Logger.
Extension-функции vs обычные методы
-
Extension-функции не могут переопределить методы класса;
-
Если у класса уже есть метод с таким именем — будет вызван именно оригинальный метод, а не extension;
-
Extension-функции не имеют доступа к private и protected членам расширяемого класса.
Использование с Generics
fun <T> List<T>.secondOrNull(): T? {
return if (this.size > 1) this\[1\] else null
}
val list = listOf("a", "b", "c")
println(list.secondOrNull()) // b
Extension-поля?
В Kotlin нельзя добавить новое поле через extension. Только методы (или свойства, реализованные через геттер).
val String.firstChar: Char
get() = this\[0\]
val c = "Scala".firstChar // 'S'
Часто используемые расширения
Kotlin стандартная библиотека содержит множество extension-функций:
-
"Hello".length
-
"text".substring(1..3)
-
listOf(1,2,3).joinToString(", ")
-
mapOf("a" to 1).keys
В Android
Расширения активно используются:
fun Context.toast(message: String) {
Toast.makeText(this, message, Toast.LENGTH_SHORT).show()
}
context.toast("Привет!")
Таким образом, extension-функции в Kotlin — это мощный инструмент для расширения функциональности типов без модификации их исходного кода. Они позволяют писать лаконичный, читаемый и выразительный код, следуя принципам функционального и объектно-ориентированного стилей.