Kotlin function declaration: equals sign before cu

2019-01-26 03:32发布

问题:

In Kotlin, the function declaration syntax allows you to write equals sign before the curly braces. Consider these two examples:

  1. Without = sign:

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

    The code inside the body gets executed by just calling foo().

  2. With = sign:

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

    Here, when foo() is called, nothing happens, but to get the body executed one can write foo()().

What is the difference in these two declarations and why do they behave differently?


This question, though having not much meaning, is intentionally asked and answered by the author, because a few questions have already been posted where people got problems because of incorrect function definitions.

回答1:

Despite visual similarity, the idea of these two declarations is completely different.

  1. Function declaration without equals sign is a Unit-returning function (similar to Java's void functions).

    What's inside the curly braces is its body, which gets executed right on the function call. The function can be rewritten with Unit explicitly specified:

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

    Kotlin doesn't require the return statement and explicit return type for Unit-returning functions, and both are usually omitted.

  2. Function declaration with equals sign is a single-expression function, and what it does is just return what's to the right of equals sign.

    A simpler example: fun getInt() = 1 is just a shorter form of fun getInt(): Int { return 1 }.

    In foo, the expression is a lambda, and it is only returned, not executed.

    Return type of foo is () -> Unit, a function itself, and thus foo is a higher-order function.

    Without the syntactic sugar and with explicit type, foo can be rewritten as

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

    As to the usage, the function which foo returns can be stored in a variable, passed around and can later be invoked:

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

    This is also why foo()() in the example executes the code from the lambda body.