Инфиксные функции в Kotlin

Инфиксные функции в Котлине

1. Вступление

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

Это, в свою очередь, значительно облегчает поддержку нашего кода и обеспечивает лучший конечный результат нашей разработки. Infix notation - одна из таких функций.

2. Что такое инфиксная нотация?

Kotlin позволяет вызывать некоторые функции без использования точки и скобок. These are called infix methods, and their use can result in code that looks much more like a natural language.с

Чаще всего это видно во встроенном определенииMap:

map(
  1 to "one",
  2 to "two",
  3 to "three"
)

“to” может выглядеть как специальное ключевое слово, но в этом примере это методto(), использующий инфиксную нотацию и возвращающийPair<A, B>.

3. Инфикс-функции общей стандартной библиотеки

Помимо функцииto(), используемой для создания экземпляровPair<A, B>, есть некоторые другие функции, которые определены какinfix.

Например, различные числовые классы -Byte,Short, Int, иLong - все определяют побитовые функцииand(), or(), shl(), shr(), ushr(), иxor(),, позволяющие использовать некоторые более читаемые выражения:

val color = 0x123456
val red = (color and 0xff0000) shr 16
val green = (color and 0x00ff00) shr 8
val blue = (color and 0x0000ff) shr 0

КлассBoolean определяет логические функцииand(), or() иxor() аналогичным образом:

if ((targetUser.isEnabled and !targetUser.isBlocked) or currentUser.admin) {
    // Do something if the current user is an Admin, or the target user is active
}

КлассString также определяет функцииmatch иzip как инфиксные, что позволяет использовать некоторый простой для чтения код:

"Hello, World" matches "^Hello".toRegex()

Есть несколько других примеров, которые можно найти в стандартной библиотеке, но они, возможно, являются наиболее распространенными.

4. Написание собственных инфиксных методов

Часто нам нужно написать собственные инфиксные методы. These can be especially useful, for example, when writing a Domain Specific Language for our application, что делает код DSL более читаемым.

Несколько библиотек Kotlin уже используют это с большим эффектом.

Например, библиотекаmockito-kotlin определяет некоторые инфиксные функции -doAnswer,doReturn, иdoThrow — для использования при определении фиктивного поведения.

Написание инфиксной функции - это простой случай следующих трех правил:

  1. Функция либо определена на class, либо является методом расширения для class

  2. Функция принимает ровно один параметр

  3. Функция определяется с помощью ключевого словаinfix

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

class Assertion(private val target: T) {
    infix fun isEqualTo(other: T) {
        Assert.assertEquals(other, target)
    }

    infix fun isDifferentFrom(other: T) {
        Assert.assertNotEquals(other, target)
    }
}

This looks simple and doesn’t seem any different from any other Kotlin code. Однако наличие ключевого словаinfix позволяет нам писать такой код:

val result = Assertion(5)

result isEqualTo 5 // This passes
result isEqualTo 6 // This fails the assertion
result isDifferentFrom 5 // This also fails the assertion

Сразу же, это чище для чтения и легче для понимания.

Note that infix functions can also be written as extension methods to existing classes. Это может быть мощным, так как позволяет нам расширять существующие классы из других источников, включая стандартную библиотеку, в соответствии с нашими потребностями.

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

infix fun String.substringMatches(r: Regex) : List {
    return r.findAll(this)
      .map { it.value }
      .toList()
}

val matches = "a bc def" substringMatches ".*? ".toRegex()
Assert.assertEquals(listOf("a ", "bc "), matches)

5. Резюме

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

Как всегда, фрагменты кода можно найти наover on GitHub.