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

Что такое also?

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

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

🐱
deepseek-v3.2PrepBro AI6 апр. 2026 г.(ред.)

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

Что такое also в Kotlin

also — это одна из функций расширения (extension function) стандартной библиотеки Kotlin, предназначенная для выполнения дополнительных действий с объектом в цепочке вызовов без изменения его основного состояния. Она относится к категории scope functions (функций области видимости), таких как let, run, with, apply.

Основное назначение и поведение

Функция also принимает объект в качестве контекста (this) и выполняет блок кода, переданный как лямбда-выражение. Ключевая особенность: она возвращает сам исходный объект (не результат выполнения блока), что позволяет использовать её для "побочных" операций, таких как логирование, валидация, модификация внешних зависимостей, без нарушения основного потока данных.

Синтаксис:

public inline fun <T> T.also(block: (T) -> Unit): T {
    block(this)
    return this
}

Пример использования

Рассмотрим практический пример создания объекта User с дополнительной операцией логирования:

data class User(val name: String, val age: Int)

val user = User("Алексей", 30)
    .also { println("Создан пользователь: $it") } // побочное действие
    .also { require(it.age >= 0) } // валидация

// user остаётся исходным объектом User("Алексей", 30)

Ключевые характеристики

  1. Контекст выполнения: внутри лямбды also объект доступен как it (по умолчанию), поскольку лямбда принимает параметр. Это отличает also от apply, где контекст — this.
  2. Возвращаемое значение: всегда возвращается оригинальный объект (this). Это особенно полезно при цепочной обработке, когда нужно сохранить оригинал для дальнейших операций.
  3. Идиоматическое применение: обычно используется для операций, которые не должны изменять состояние объекта, но должны быть выполнены в процессе его создания или обработки.

Сравнение с другими scope functions

ФункцияКонтекстВозвращаетОсновное применение
alsoit (параметр)исходный объектпобочные действия, логирование, валидация
applythis ( receiver )исходный объектконфигурация объекта, установка свойств
letit (параметр)результат лямбдыпреобразование объекта, безопасные вызовы
runthis ( receiver )результат лямбдывыполнение операций и возврат результата

Пример сравнения:

// also - возвращает исходный объект, выполняет побочное действие
val list1 = mutableListOf(1, 2, 3)
    .also { it.add(4) } // изменяет список, но возвращает исходный объект
    .size // size = 4, но list1 - это всё тот же список

// apply - также возвращает исходный объект, но контекст - this
val list2 = mutableListOf(1, 2, 3)
    .apply { add(4) } // внутри this.add(4)
    .size // аналогично

Практические сценарии использования

  1. Логирование промежуточных состояний:
val processedData = data
    .filter { it.isValid }
    .also { logger.debug("Отфильтровано ${it.size} элементов") }
    .map { it.transform() }
  1. Валидация или проверки:
val configuration = loadConfig()
    .also { requireNotNull(it.apiKey) { "API ключ отсутствует" } }
  1. Регистрация или подписка в сторонних системах:
val newObserver = Observer()
    .also { eventBus.register(it) } // регистрируем, но продолжаем работать с observer
  1. Настройка объектов с побочными эффектами (альтернатива apply, когда нужен параметр it):
val button = Button(context)
    .also { 
        it.text = "Нажать"
        it.setOnClickListener { /* обработка */ }
    }

Особенности и рекомендации

  • Не изменяйте состояние объекта в also в идеальном случае, хотя технически это возможно. Для модификации объекта лучше использовать apply.
  • Используйте also для "чистых" побочных эффектов, которые не влияют на основной поток данных.
  • Избегайте чрезмерного использования в цепочках, чтобы не создавать "спагетти-код".
  • Имя параметра можно изменять для улучшения читаемости:
user.also { newUser -> 
    println(newUser)
    database.insert(newUser)
}

В заключение, also — это мощный инструмент для декларативного и цепочного стиля программирования в Kotlin, позволяющий выполнять побочные операции без нарушения основного потока преобразования данных. Его правильное использование повышает читаемость и поддерживаемость кода, особенно в комбинации с другими scope functions.