Kotlin известен своим кратким, но последовательным синтаксисом.

Добавить значение в список в Kotlin так же просто, как:

val k = listOf(1, 2) + 3
println(k) // [1, 2, 3]

Но что, если мы хотим добавить значение в список?

В Scala для этого есть оператор ::.

val s = 1 :: List(2, 3)

На самом деле это функция с именем :, а второе двоеточие означает, что функция fill работает с первым

Итак, это можно примерно перевести на

val s = List(2, 3).::(1)

Хотя на самом деле это больше похоже на

val s = ::(1, List(2, 3))

Где :: - это имя класса case (класс данных в Kotlin)

Что-то подобное не будет работать в Котлине:

val k = 1 + listOf(2, 3) // Doesn’t compile

И, как обычно в серии «Взлом с Kotlin», должен быть вопрос: «сможем ли мы этого добиться?

Первое решение, которое приходит на ум, - это комбинация операторной функции и функции расширения.

В конце концов, именно так в Kotlin работает объединение со списком.

Мы могли бы сделать что-то в этом роде:

operator fun <T> T.plus(tail: List<T>): List<T> {
    val list = ArrayList<T>(1 + tail.size)

    list.add(this)
    list.addAll(tail)

    return list
}

Что теперь дает ожидаемые результаты:

val k = 1 + listOf(2, 3) // [1, 2, 3]

Другой вариант, который будет короче, но немного менее эффективен:

operator fun <T> T.plus(tail: List<T>): List<T> {
    return mutableListOf(this).apply {
        addAll(tail)
    }
}

Что можно было бы сделать еще короче, используя функцию одного выражения:

operator fun <T> T.plus(tail: List<T>) = mutableListOf(this).apply {
    addAll(tail)
}

И если мы ограничимся только конкретными типами, скажем числами, мы могли бы сделать даже что-то вроде этого:

operator fun Number.plus(tail: List<Number>) = listOf(this) + tail

Выводы

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

Есть ли лучшие решения той же проблемы? Делитесь ими в комментариях.