Инфиксная нотация

Последнее обновление: 02.03.2024

Инфиксная нотация представляет помещение оператора или функции перед операндами или аргументами. Инфиксная нотация часто применяется для определения математических и логических выражений. К примеру, выражение (+ a b) представляет инфиксную нотацию записи суммы чисел a + b.

Для определения инфиксной функции вначале ее определения указывается ключевое слово infix:

infix fun название_функции(параметр: тип_параметра): тип_возвращаемого_значения{
	// действия функции
}

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

Есть два способа определения инфиксной функции: либо внутри класса, либо как функции расширения.

Определим вначале внутри класса:

fun main() {

    val acc = Account(1000)
    acc put 150
	// равноценно вызову
	acc.put(150)
    acc.printSum()  // 1300
}
class Account(var sum: Int) {

    infix fun put(amount: Int){
        sum = sum + amount
    }
    fun printSum() = println(sum)
}

Здесь определен класс Account - класс банковского счета, который через конструктор принимает начальную сумму на счете. С помощью инфиксной функции put() определяем добавление на счет суммы, переданной через параметр функции.

Вызов функции выглядит следующим образом:

acc put 150

Первый параметр (здесь переменная acc) представляет объект, который вызывает функцию. А второй параметр - данные, которые непосредственно будут передаваться инфиксной функции через ее параметр. То есть данный вызов фактически аналогичен вызову:

acc.put(150)

Также инфиксная функция может определяться как функция расширения. Например, перепишем выше использованную функцию put() в виде функции расширения:

fun main() {

    val acc = Account(1000)
    acc put 150
    acc.put(150)
    acc.printSum()  // 1300
}
infix fun Account.put(amount: Int){
    this.sum = this.sum + amount
}
class Account(var sum: Int) {
    fun printSum() = println(sum)
}

Стоит отметить, что функция расширения в отличие от функции внутри класса имеет доступ только тем свойствам, которые являются публичными.

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

fun main() {

    val hello = "hello world"
    val lCount = hello wordCount 'l'
    val oCount = hello wordCount 'o'
    println(lCount)   // 3
    println(oCount)   // 2
}

infix fun String.wordCount(c: Char) : Int{
    var count = 0
    for(n in this){
        if(n == c) count++
    }
    return count
}

Здесь функция wordCount проходит по всем символам строки и подсчитывает, сколько раз встречается символ, передаваемый через параметр функции. Результат возвращается функцией. Затем мы можем применить инфиксную нотацию:

val lCount = hello wordCount 'l'

Поскольку функция возвращает результат типа Int, то мы можем получить этот результат в переменную.

Инфиксная функция позволяет задать способ описания действия, более близкий к естественному языку. Например:

fun main() {

    val tom = Person("Tom")
    tom says "Hello"
}
class Person(val name: String) {

    infix fun says(words: String){
        println("$name says: ${words}")
    }
}

Здесь определен класс Person, который представляет человека и который через параметр name конструктора получает имя человека. В этом классе в виде инфиксной функции определен метод "says", который принимает параметр words - это условные слова, которые произносит человек.

Для вызова метода says мы можем написать следующим образом:

tom says "Hello"

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

tom.says("Hello")

И не только на английском. Например:

fun main() {

    val Том = Person("Tom")
    Том говорит "Привет"
}
class Person(val name: String) {

    infix fun говорит(words: String){
        println("$name говорит: ${words}")
    }
}
Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850