Summary of Kotlin function knowledge

Closure

A closure is a runtime environment that contains functions. Classes can be defined in functions, and the runtime environment of functions pointed to by a closure will not be recycled.

fun makeFun(): () -> Unit {
    var count = 0
    return fun() {
        println(++count)
    }
}

fun main(args: Array<String>) {
    val x = makeFun() 
    x() // 1
    x() // 2
    x() // 3
    x() // 4
    x() // 5
}

From the above example, it can be seen that what the makeFun method returns is actually a function, and the local variable count of the makeFun function saves the current operation value, and the value of the function count returned by continuous calls also increases accordingly. This means that count is not reclaimed after the function is called and is still stored in memory, and subsequent calls will use the same memory variable.

fun fibonacci(): () -> Long {
    var first = 0L
    var second = 1L

    return fun(): Long {
        val result = second
        second += first
        first = second - first
        println(result)
        return result
    }
}

fun main(args: Array<String>) {
    val x = fibonacci()
    x() // 1
    x() // 1
    x() // 2
    x() // 3
    x() // 5
    x() // 8
}

This Fibonacci sequence implementation also includes local variables in the external function. The returned function uses these two local variables, and when the returned function is called, the local variables of the external function are still stored in memory.

The way this closure is called looks weird, why is there this weird syntax in Kotlin? In fact, there are two scopes for defining data variables in kotlin, one is global variables and the other is local variables.

var x = 100

fun hello() {
    var y = 200
    println(x)
    println(y) // 没有问题
}

fun main(args: Array<String>) {
    hello()
    println(x)
    // println(y) 编译器报错
}

From the above example, we can see that the global variable x can be accessed in any function of hello and main, but the variable y is only limited to the hello function and can be used. The scope of x is the global scope, which is the global variable, and the scope of y is only within the scope of the hello function, which is the local variable.

If the developer wants to define a variable that can only be accessed by some functions but has the life cycle of a global variable, consider defining the variable as a global variable, then the life cycle is satisfied but the variable can be accessed by other functions, and then consider defining If it becomes a local variable, then the variable disappears after the function returns. At this time, the use of closures can solve this problem well.

function composition

Consistent with the concept of conform function in mathematics, if some functions are often used in combination in kotlin, they can be conformed together to form a function, and users only need to call this function to realize complex functions.

// 普通加8
var add8 = {
    i: Int -> i + 8
}

// 普通乘积
var multiply = {
    i: Int -> i * 3
}

// 符合函数是一个中缀操作符
infix fun <P1, P2, R> Function1<P1, P2>.andThen(function: Function1<P2, R>): Function1<P1, R> {
    return fun(p1: P1): R {
        return function.invoke(this.invoke(p1))
    }
}

fun main(args: Array<String>) {
    // 将两个函数复合起来
    var add8andmultiply = add8 andThen multiply
    println(add8andmultiply(3))
}

The above composite function actually adds an extension method andThen to the Function1 type. This function includes a parameter of the Function1 type. Finally, the current function is called first and its return value is used as a parameter to call the incoming function. Here, the closure syntax is used to call this call. Made a new function return.

Currying

Turning a multi-source function into a chained call of multiple unary functions actually still uses the syntax of closures, constantly returning new functions until all parameters are used up.

// 原始版本
fun save(table: String, id: Int, name: String, age: Int) {
    println("insert into $table values($id, '$name', $age)")
}

// 直接返回函数版本
fun save(table: String): (Int) -> (String) -> (Int) -> Unit {
    return fun(id: Int): (String) -> (Int) -> Unit  {
        return fun(name: String): (Int) -> Unit {
            return fun(age: Int) {
                println("insert into $table values($id, '$name', $age)")
            }
        }
    }
}

// 简写版本
fun save(table: String) = fun(id: Int) = fun(name: String) = fun(age: Int) =
        println("insert into $table values($id, '$name', $age)")

fun main(args: Array<String>) {
    // 原始调用方式
    save("tb_user", 10, "zhangsan", 20)
    // curry调用方式
    save("tb_user")(10)("zhangsan")(20)
}

partial function

Passing some parameters to the function to get a new function, in order to achieve this function, the previous currying is useful.

fun save(table: String) = fun(id: Int) = fun(name: String) = fun(age: Int) =
        println("insert into $table values($id, '$name', $age)")
val saveUser = save("tb_user")
saveUser(20)( "lishi")( 30)

In this example, an operation to save to the user table is defined, that is to say, the first parameter is always the "tb_user" data table. In the previous currying implementation, the returned result is actually a closure function, and you can use saveUser directly. this partial function.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325615003&siteId=291194637