ПрограммированиеKotlin мобильный разработчик

Что такое расширения (extension functions) в Kotlin и как их правильно использовать? Опишите подводные камни применения и дайте пример кода.

Проходите собеседования с ИИ помощником Hintsage

Ответ.

Extension functions/расширения — это механизм, позволяющий добавлять новые функции в уже существующие классы без необходимости наследования или изменения самого класса.

Например, для класса String, добавим функцию, переворачивающую строку:

fun String.reverse(): String { return this.reversed() } println("abc".reverse()) // "cba"

Расширения на самом деле не модифицируют класс, а просто являются синтаксическим сахаром: они компилируются как статические методы, принимающие экземпляр объекта как первый параметр.

Преимущества: лаконичность, читаемость, расширяемость кода. Хорошо ложатся на utility-функции для коллекций, строк и т.д.

Подводные камни:

  • Не могут переопределять/замещать методы класса;
  • Нет доступа к приватным членам класса;
  • При конфликте имён побеждает метод экземпляра, а не расширения;
  • Extension property работает только с getter/setter, не с полями;

Вопрос с подвохом.

Можно ли при помощи extension functions добавить новую переменную (property), хранящую состояние, к классу?

Ответ: Нет. Extension property — это всегда вычисляемое свойство (getter/setter), не поле. Они не могут хранить состояние — только вычислять на лету.

val String.secondChar: Char get() = this[1] // Только вычисление, не хранение!

Примеры реальных ошибок из-за незнания тонкостей темы.


История

В проекте по верификации данных разработчик добавил extension property к модельному классу как если бы оно хранило значение, но позже заметил, что значение всегда вычисляется, а не запоминается, из-за чего логика работала неверно при многократных вызовах.


История

В большом приложении расширения были названы так же, как методы класса, что привело к путанице: методы класса всегда имели приоритет, а расширения не вызывались — потрачен день на отладку "невидимого" кода.


История

В одной из библиотек расширения использовались для приватных полей класса, но позже оказалось, что они вообще не имеют прав доступа к private, из-за чего приходилось рефакторить архитектуру моделей.