Extension property в Kotlin — какво е, синтаксис и приложение

Автор: IT Sectr Публикувано: 2026-06-21 Време за четене: 8 мин

extension property — механизъм в Kotlin, който позволява да добавяте нови свойства към съществуващи класове без наследяване и без промяна на изходния код. За разлика от extension functions, свойствата-разширения не могат да съхраняват състояние — те се декларират само с getter и опционално setter, тъй като нямат backing field. Според Kotlin Documentation, 2025, extension properties се компилират в статични методи getter и setter с receiver като първи параметър.

Основни моменти

  • Extension property — свойство с receiver type, достъпно чрез синтаксиса на свойствата на Kotlin
  • Няма backing field — extension property не може да съхранява състояние, само да изчислява
  • Getter е задължителен, setter е опционален — декларират се като обикновени extension functions
  • Nullable типове се поддържат: receiver може да бъде nullable с вътрешна проверка
  • Mutable extension property — само при декларация var с getter и setter

Какво е extension property в Kotlin?

extension property — е синтактична конструкция на Kotlin, която добавя свойство към съществуващ тип, без да променя неговата декларация. Свойството се декларира с посочване на receiver-типа и задължително съдържа getter. Ключовата разлика от обикновените свойства — липсата на backing field: extension property не може да съхранява данни, а ги изчислява на базата на receiver-обекта.

Според Kotlin Foundation Survey (2024), extension properties са по-малко популярни от extension functions — около 45% от разработчиците ги използват редовно. Това се дължи на ограничението за липса на състояние, което стеснява областта на приложение. Въпреки това, за изчислявани свойства, които са логически свързани с типа, extension properties са най-краткият вариант.

Extension properties се компилират в двойка статични методи getter и setter. На ниво на байткод няма разлика между извикването на extension property и extension function — и двете стават статични методи с параметър receiver. Според данни на JetBrains (Kotlin Docs, 2025), допълнителното натоварване е напълно липсващо.

Използвайте extension properties за къси изчислявани стойности, които трябва да изглеждат като свойства, а не като извиквания на методи — това подобрява четимостта на кода и спазва принципа за единен достъп.

Синтаксис на extension property: val и var

За декларация на extension property се използва синтаксис, подобен на обикновено свойство, но с префикс на receiver-типа. val декларира read-only extension property с задължителен getter, var — mutable с getter и опционален setter.

kotlin
// Само за четене extension property
val String.isEmail: Boolean
    get() = this.contains("@") && this.contains(".")

// Извикване
val valid = "test@test.com".isEmail

Обратете внимание: extension property се извиква без скоби — str.isEmail, а не str.isEmail(). Това е ключовата разлика между extension property и extension function: property изглежда като поле, въпреки че всъщност се изчислява чрез getter.

Generic extension property

Extension properties могат да бъдат обобщени — receiver може да използва generic параметри. Това позволява създаване на универсални свойства, които работят с всеки тип колекция.

kotlin
val List<T>.secondOrNull: T?
    get() = if (size >= 2) this[1] else null

val items = listOf("a", "b", "c")
val second = items.secondOrNull // "b"

Свойството secondOrNull работи за всеки тип T, връщайки втория елемент на списъка или null, ако има по-малко от два елемента. Това е типичен пример, където extension property е по-подходяща от функция — достъпът изглежда като четене на поле.

Защо extension property не може да съхранява състояние

Extension property не може да има backing field, защото не се добавя към метаданните на класа — съществува само като двойка статични функции getter/setter. Backing field (ключовата дума field в Kotlin) — е вътрешното поле на класа, което съхранява стойността на свойството. Extension property няма достъп до вътрешната структура на класа.

kotlin
// ❌ ГРЕШКА: extension property не може да има backing field
var String.cachedValue: String
    get() = "computed"
    set(value) {
        field = value // полето не е достъпно!
    }

// ✅ ПРАВИЛНО: използвайте външно съхранилище
val cache = MutableMap<String, String>()

var String.cachedValue: String
    get() = cache[this] ?: ""
    set(value) { cache[this] = value }

Външният Map в примера решава проблема с съхраняването, но създава друг — изтичане на памет. Стойностите, получени чрез extension property, живеят в Map завинаги, ако не бъдат почистени. Това ограничение прави extension properties неподходящи за кеширане или съхраняване на временни данни.

За кеширане се препоръчва използването на WeakHashMap или механизми с автоматично почистване. JetBrains препоръчва да се избягва използването на var extension properties с външно съхранилище в производствен код без внимателно управление на жизнения цикъл.

Extension property vs extension function: кога какво да изберем

Изборът между extension property и extension function зависи от семантиката: свойството описва характеристика на обекта, а функцията — действие. Принципът за единен достъп (Uniform Access Principle) казва: клиентът не трябва да знае дали стойността се изчислява или съхранява. Ако стойността може да бъде представена като характеристика (дължина, размер, състояние) — използвайте property.

КритерийExtension propertyExtension function
ИзвикванеБез скоби: obj.propertyС скоби: obj.function()
СемантикаХарактеристика, атрибутДействие, операция
Backing fieldНе се поддържаНе приложимо
ПараметриСамо getter/setterВсички параметри
ПроизводителностЕднаква (статичен метод)Еднаква (статичен метод)
Примерtext.lengthtext.isEmail()

Правилото е просто: ако операцията приема параметри — използвайте extension function. Ако става въпрос за проста изчислявана стойност без параметри — extension property. Според Android Architecture Guide (Google, 2025), предпочтание трябва да се дава на extension properties за достъп до данни и на extension functions за операции с нежелани ефекти.

Mutable extension property с var и setter

Extension property с ключовата дума var поддържа setter, но без възможност да съхранява стойност — setter обикновено извършва нежелан ефект или запазва данни в външно съхранилище. Синтаксисът е аналогичен на mutable свойствата на класовете.

kotlin
// Mutable extension property с setter
var StringBuilder.lastChar: Char
    get() = this[length - 1]
    set(value) {
        this.setCharAt(length - 1, value)
    }

val sb = StringBuilder("Kotlin")
println(sb.lastChar) // n
sb.lastChar = '!'
println(sb) // Kotli!

Свойството lastChar — класически пример от документацията на Kotlin. Getter връща последния символ на StringBuilder, setter го замества с нова стойност. Обратете внимание: състоянието се съхранява в самия StringBuilder (чрез setCharAt), а не в отделно поле — това е правилно използване на extension property.

Практически примери на extension properties

В реални проекти extension properties се използват най-често за опростяване на достъпа до данни от колекции, изчисляване на размери или състояния на UI елементи и създаване на удобно API върху съществуващи класове. Стандартната библиотека на Kotlin активно използва този механизъм: size, indices, lastIndex за колекции — това са extension properties.

kotlin
// Extension properties за колекции
val List<Int>.sumFast: Int
    get() = fold(0) { acc, i -> acc + i }

val String.half: String
    get() = this.substring(0, length / 2)

// Extension property за Android View
val View.isVisible: Boolean
    get() = visibility == View.VISIBLE

// Null проверка чрез безопасен receiver
val String?.isNullOrBlank: Boolean
    get() = this == null || this.isBlank()

Extension property isVisible за View — пример, който всеки Android разработчик трябва да знае. Вместо view.visibility == View.VISIBLE може да пишете view.isVisible. Това е не само по-кратко, но се чете като естествен език: „ако прозоръ0446ъ0442 е видим“. Въпреки простотата си, такива свойства значително подобряват четимостта на кода.

Често задавани въпроси

Може ли да декларирам extension property за companion object?

Не, extension properties не могат да бъдат декларирани за companion object или object declaration. Механизъмът extension се прилага само към класове, интерфейси и nullable типове. За object използвайте обикновени функции на най-високо ниво.

По какво се различава extension property от inline свойство?

Inline свойство (с модификатор inline) — механизъм на Kotlin за извикване на getter/setter без създаване на обект-свойство. Extension property винаги се компилира в статичен метод, а inline свойството се компилира в извикване без обвивка. Те решават различни задачи: extension property добавя свойство към съществуващ тип, inline оптимизира извикванията на собствени свойства.

Поддържат ли extension properties анотации?

Да, extension property може да съдържа анотации, но само на ниво на декларация. Getter или setter на extension property не могат да бъдат анотирани отделно — за разлика от обикновените свойства на класа. Пример: @JvmName(„gетIсVалид“) val String.isValid get() = true.

Може ли да използвам extension property с companion object на класа?

Не, extension properties не могат да бъдат декларирани с companion object като receiver. Това е ограничение на езика — extension property работи само с инстанции на типове, а companion object е статичен контекст. Използвайте extension functions на най-високо ниво или константи.

Влияе ли extension property върху размера на APK?

Минимално. Всяка extension property добавя един статичен getter метод (и опционален setter) към компилирания байткод. За сравнение: създаването на обвиващ клас с същото свойство добавя цял клас. Extension properties — по-лек подход за разширяване на функционалността.

Резюме

  • Extension property — изчислявано свойство за съществуващ тип без наследяване
  • Няма backing field — състоянието не се съхранява, само се изчислява чрез getter
  • var с setter — възможно, но изисква външно съхранилище за запис на данни
  • Синтаксис — val/var с receiver-тип и задължителен getter
  • Производителност — нулево натоварване, компилира се в статичен метод
  • Приложение — изчислявани характеристики: дължина, състояние, размер, проверки
  • Ограничение — не подходящо за съхраняване на състояние, кеширане без управление на паметта

Ще разработим мобилно приложение под ключ

IT Sectr създава iOS и Android приложения за стартъпи и бизнеси от 2017 г. Ще ви консултираме и ще предложим най-доброто решение.

Обсъдете проекта

Прочетете също