Объявление функции Kotlin: знак равенства перед фигурными скобками

В Kotlin синтаксис объявления функции позволяет писать знак равенства перед фигурными скобками. Рассмотрим эти два примера:

  1. Без = знак:

    fun foo() {
        bar()
        println("baz")
    }
    

    Код внутри тела исполняется простым вызовом foo(),

  2. С = знак:

    fun foo() = {
        bar()
        println("baz")
    }
    

    Здесь, когда foo() называется, ничего не происходит, но для выполнения тела можно написать foo()(),

В чем разница в этих двух декларациях и почему они ведут себя по-разному?


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

1 ответ

Решение

Несмотря на визуальное сходство, идея этих двух объявлений совершенно другая.

  1. Объявление функции без знака равенства Unit функция возврата (аналогично Java void функции).

    Внутри фигурных скобок находится его тело, которое выполняется прямо при вызове функции. Функция может быть переписана с Unit явно указано:

    fun foo(): Unit {
        bar()
        println("baz")
        return Unit
    }
    

    Котлин не требует оператора возврата и явного типа возврата для Unit -возвратные функции, и оба обычно опускаются.

  2. Объявление функции со знаком равенства является функцией с одним выражением, и она просто возвращает то, что находится справа от знака равенства.

    Более простой пример: fun getInt() = 1 это просто более короткая форма fun getInt(): Int { return 1 },

    В foo, выражение является лямбда- выражением, и оно только возвращается, но не выполняется.

    Тип возврата foo является () -> Unit, сама функция, и, таким образом, foo является функцией высшего порядка.

    Без синтаксического сахара и с явным типом, foo может быть переписан как

    fun foo(): () -> Unit {
        val result: () -> Unit = { bar(); println("baz") }
        return result
    }
    

    Что касается использования, функция, которая foo возврат может быть сохранен в переменной, передан и позже может быть вызван:

    val f = foo()
    
    f() //equivalent to
    f.invoke()
    

    Это также почему foo()() в примере выполняется код из лямбда-тела.

Другие вопросы по тегам