Kotlin Basic Grammar 13, Lambba Expression Analysis 4 (Grammar)

1. Lambda expression syntax

Looking back at the previous article, we need to run a function somewhere. We only know the parameter type and return value type of this function (the parameter type plus the return value type constitute a special data type in Kotlin: function type), but the function We don't care about the specific operation, so we dynamically pass a function that meets the parameter type and return value type conditions, but only objects can be passed as parameters, so we use double colons or anonymous functions to implement a function type object. However, the code of these two methods is relatively cumbersome. In order to simplify the amount of code and make the code concise and clear, we introduced Lambda expression, so the essence of Lambda expression is actually a function type object. Our real appeal is to have a dynamically set method.

Example: There is now a method a whose parameter type is a function type

fun a(fb : (Int , String) -> String) {
    
    

}

In order to call method a, we need to pass in an object of function type.
We generally have two methods:

  1. You can use double colons:
fun b(p1 : Int , p2 : String) : String {
    
    
    return p2 + p1
}
a(::b)
  1. Use anonymous functions
val b : (Int , String) -> String = fun(p1 : Int , p2 : String) : String {
    
    
    return p2 + p1
}
a(b)

Of course, you can also pass the anonymous function directly:

a(fun(p1 : Int , p2 : String) : String {
    
    
    return p2 + p1
})

You can see that the anonymous function method is too cumbersome. Next, we introduce Lambda expressions to simplify it.

1.) The format of Lambda expression is as follows:
{Parameter 1: Parameter type, Parameter 2: Parameter type,... -> Execution code block}

Note: The last line of expression in the execution code block is the return value of the Lambda expression
. This expression The return type must be consistent with the declared return value type.

So we can use Lambda expression to express the above anonymous function as:

a({
    
     p1 : Int , p2 : String ->
    p2 + p1
})

2.) When we have explicitly declared the function type of the lambda, we can omit the type of the parameters in the lambda parameter list,
so it can be simplified to:

a({
    
     p1 , p2 ->
    p2 + p1
})

3.) When the lambda expression is used as the last actual parameter of the function call, it can be placed outside the parentheses,
so it can be simplified to:

a() {
    
     p1 , p2 ->
    p2 + p1
}

4.) When lambda is the only actual parameter of the function, the empty brackets of the function can also be removed,
so it can be simplified to:

a {
    
     p1 , p2 ->
    p2 + p1
}

After continuous simplification, this is the most common form in our daily life.
5.) When there is only one parameter in the lambda expression, and the type of this parameter can be deduced, the default parameter name it will be generated to replace this parameter. At this time, we do not need to explicitly declare the name of the parameter, which means that we can Omit it.
Example is as follows:

fun a(fb : (Int ) -> String) {
    
    

}
a{
    
    
    it.toString()
}

Note: When multiple lambdas are nested, it is best to explicitly declare the parameters of each lambda expression, otherwise it will be difficult to figure out what value it refers to, seriously affecting the readability of the code.
6.) When using Lambda expressions, you can use an underscore (_) to indicate unused parameters in the execution code block, indicating that this parameter will not be processed.

a {
    
     _ , p2 ->
    p2
}

2. SAM conversion

In the previous article, we also mentioned the method of transferring functions in Java using interfaces. Kotlin also provides lambda syntax for interfaces, which is SAM conversion:

  1. SAM conversion only works on interfaces, not on abstract classes, even these abstract classes have only one abstract method.

  2. It must be a functional interface, that is, an interface declared using fun interface. This interface can only have one abstract method (obviously, the ultimate goal of lambda expression is to have a dynamic function).
    SAM conversion is to convert lambda to function explicitly. Functions generated from interface instances

  3. Functional interfaces and function types are not the same thing . This is easy to understand. One is an interface and the other is a data type. They cannot be mixed.

An example is as follows: We define a functional interface

fun interface Click {
    
    
    fun click(a : Int) : String
}
fun a(c : Click) {
    
    
    c.click(1)
}

Without using lambda, for convenience, we generally use object expressions to construct an object of an anonymous inner class and pass it in

a(object : Click {
    
    
    override fun click(a : Int) : String {
    
    
        return a.toString()
    }
})

Use lambda and the syntax is not any different from the one mentioned above

a {
    
     a -> a.toString() }

Guess you like

Origin blog.csdn.net/weixin_43864176/article/details/123905674