With the receiver in scope — заметка Романа Элизарова из команды разработчиков Kotlin о ключевой функции with.
Другие полезные статьи на тему Kotlin:
- Как сделать код на Kotlin более понятным
- Шпаргалка по коллекциям Kotlin
- Хорошие и плохие приемы программирования на Kotlin
- Основы функционального программирования на Kotlin
Представьте, что у вас есть следующий код:
1 2 3 4 |
applicationWindow.title = "Just an example" applicationWindow.position = FramePosition.AUTO applicationWindow.content = createContent() applicationWindow.show() |
Несмотря на корректность и в целом удовлетворительную читаемость, код выглядит громоздким. Его долго печатать, долго читать, и легко допустить ошибку (например, если у вас весть еще один объект с похожим на applicationWindow именем). Используя with, мы можем решить все эти проблемы:
1 2 3 4 5 6 |
with(applicationWindow) { // this: ApplicationWindow title = "Just an example" position = FramePosition.AUTO content = createContent() show() } |
Этот код на две строки длиннее, но он гораздо понятнее. Любой читающий этот код человек сразу видит, что все содержимое фигурных скобок относится к объекту applicationWindow.
А самое интересное, что столь полезный инструмент — это вовсе не часть языка, не ключевое слово, а функция, состоящая всего из одной строки:
1 2 |
fun <T, R> with(receiver: T, block: T.() -> R): R = receiver.block() |
По сути, эта функция просто запускает весь код в блоке в контексте указанного объекта, так же как это делают функции-расширения.
И тут назревает вопрос: если подобная функциональность настолько удобна и полезна и так легко реализуется, почему бы не использовать ее везде? Например, почему бы не делать то же самое в методах forEach, filter, map и других?
Чтобы ответить на этот вопрос, приведем два фрагмента кода. Первый:
1 |
persons.filter { it.firstName == name } |
Второй:
1 |
persons.filter { firstName == name } |
В первом фрагменте мы используем метод filter так, как он реализован в Kotlin сейчас. Во втором — так, как он мог бы быть реализован при использовании внутри функции with. Обратите внимание, что код не стал более читаемым. Напротив, он вводит в заблуждение. Что такое name? Это объявленная ранее переменная или поле, принадлежащее объекту, с которым мы работаем?
Функция with может быть очень полезна в одних случаях и полностью разрушать читаемость и открывать простор для ошибок — в других.