function

A function is a block of code organized for a specific function. The function definition format is as follows:

  • Fun :[return value type]{[function body]}
  • Fun function name = [expression]
fun sum(arg1: Int, arg2: Int): Int {
    return arg1 + arg2
}
Copy the code

If the function method body has only one line of code, we can change {} to = without return, and the value of the expression will be returned as the function value:

fun sum(arg1: Int, arg2: Int) = arg1 + arg2
Copy the code

Default return value type

Any function has a return value. In general, the method body of a function uses a return to return the result. However, some functions do not need to return the result, so you can omit the return:

fun main(args: Array<String>){... }Copy the code

Even if there is no return in the body of a function, the function still has a return value type. The default return value type is Unit, but Unit is usually omitted:

fun main(args: Array<String>): Unit{... }Copy the code

Anonymous functions

An anonymous function is a function that has no name, but needs to be assigned to a variable, otherwise the IDE will report an error:

// Sum, whose value is a function
val sum = fun(arg1: Int, arg2: Int): Int {
    return arg1 + arg2
}

fun main(args: Array<String>): Unit {
    val result = sum(1.2)
    println(result) / / 3
}
Copy the code

In this case, sum is a variable, but its value is a function.

Lambda expressions

Lambda expressions are also “anonymous functions”, but in a slightly different format:

  • {[argument list] -> [function body, last line is return value]}
val sum = { arg1: Int, arg2: Int ->
    println("$arg1 + $arg2 = ${arg1 + arg2}")
    arg1 + arg2
}

fun main(a){
    println(sum(1.2)) / / 3
}
Copy the code

The return value of a Lambda expression is the result of the last line in the expression.

The type of a Lambda

In Kotlin, both constants and variables have their own types, such as Human. If a variable’s value is a Lambda expression, what is its type? That’s right, Lambda:

  • () -> Unit: no parameter, return value null
  • (Int) -> Int: Passes an integer and returns an integer
  • (String, (String)->String) -> Boolean: Pass String, Lambda expression, return Boolean
// lambda type :(Int,Int) -> Int
val sum = { arg1: Int, arg2: Int -> arg1 + arg2 }

// lambda type :() -> Unit
val printlnHello = {
    println("Hello")}Copy the code

Calls to Lambda expressions

As with anonymous functions, a variable with a value of a Lambda expression can execute a Lambda expression in one of two ways:

  • with(a)The calling
  • withinvoke()call
println(sum(1.2)) / / 3
println(sum.invoke(1.2)) / / 3
Copy the code

Actually, () is invoke().

Simplification of Lambda expressions

  • The last Lambda can be removed when a function argument is called
  • The function argument has only one Lambda, and the parentheses can be omitted when called
  • Lambda has only one argument, which defaults to it
  • A function whose input argument returns the same value as the parameter may be passed in as an argument as a function reference

Let’s look at forEach, an extension to Array:

/** * Performs the given [action] on each element. */
public inline fun <T> Array<out T>.forEach(action: (T) - >Unit): Unit {
    for (element in this) action(element)
}
Copy the code

ForEach forEach forEach forEach forEach forEach forEach forEach forEach forEach forEach forEach forEach forEach forEach forEach forEach forEach forEach forEach forEach forEach forEach Action action of type (T -> Unit Lambda), return Unit (that is, no return value), forEach forEach forEach forEach The action argument is also used to process the iterated elements.

We won’t go into details about the extension function here, but we’ll cover it in future articles. We just need to know what forEach does.

val args = arrayOf("1"."2"."3"."l"."q"."r")

// Use for-in to iterate through the array and print the element contents
for (arg in args) {
    println(arg)
}
Copy the code

ForEach = forEach; forEach = forEach; forEach = forEach; forEach = forEach; forEach = forEach

// complete Lambda
args.forEach({ it -> println(it) })

// Lambda simplified
args.forEach({ println(it) })

// Rename the parameter it. Ele cannot be omitted
args.forEach({ ele -> println(ele) })
Copy the code

Lambda defaults to it when it has only one argument. Of course, you can rename it if you don’t want to use it, but if you rename it, you can’t omit it. In addition to omitting the default argument it, there are ways to simplify Lambda expressions:

// The last Lambda can be moved out when a function argument is called
args.forEach(){ println(it) }

// The function argument has only one Lambda, and the parentheses can be omitted when called
args.forEach{ println(it) }
Copy the code

This is the simplified version of Kotlin’s Lambda expression, and we will often encounter the final simplified version in future development.

Lambda expressions and function references

Go back to the action type of the forEach extension function:

// action: (T) -> Unit
public inline fun <T> Array<out T>.forEach(action: (T) - >Unit): Unit {
    for (element in this) action(element)
}
Copy the code

Now look at the definition of println() :

// println: (Any?) -> Unit
public actual inline fun println(message: Any?). {
    System.out.println(message)
}
Copy the code

Println () is defined as a Lambda for action. In this scenario, we can also convert the Lambda expression required by the forEach parameter action into a reference to the println function, which uses :: :

// A function whose input parameter returns the same value as its parameter can be passed in as an argument as a function reference
args.forEach(::println)
Copy the code

Lambda expressions jump out of forEach

Here is a serious superclass, do not understand it does not matter, you can skip ~

Requirement: When iterating through a group of numbers, break the loop when an element q is found.

val args = arrayOf("1"."2"."3"."l"."q"."r")
for (arg in args) {
    if (arg == "q") break
    println(arg)
}
println("The End") // 1 2 3 l The End
Copy the code

ForEach = forEach = forEach = forEach = forEach = forEach

fun main(a) {
    val args = arrayOf("1"."2"."3"."l"."q"."r")
    args.forEach {
        if (it == "q") break // IDE error: 'break' and 'continue' are only allowed inside a loop
        print("$it ")
    }
    println("The End")}Copy the code

Lambda expressions are just expressions, not loops, so we can’t use break and continue, so we have to use return to interrupt the loop:

fun main(a) {
    val args = arrayOf("1"."2"."3"."l"."q"."r")
    args.forEach { // 1 2 3 l
        if (it == "q") return
        print("$it ")
    }
    println("The End") // Will not be executed
}
Copy the code

At first glance, The use of return for interrupt traversal looks like it, but The absence of “The End” means that The return does not interrupt traversal, but rather interrupts The current main function for The same reason: Lambda expressions are just expressions.

For Lambda expressions, Kotlin provides labeled returns, which can be used to jump out of traversal using the return@xxx method in Lambda expressions. Try this:

fun main(a) {
    val args = arrayOf("1"."2"."3"."l"."q"."r")
    args.forEach {
        if (it == "q") return@forEach
        print("$it ")
    }
    println("The End") // 1 2 3 l r The End
}
Copy the code

What happens when the program skips q and continues? This goes back to the nature of Lambda expressions. A Lambda expression in forEach is actually a function body, so the tag return return@xxx exits the function body only by exiting the current call. Is there no way to implement this requirement using forEach? Yes, forEach alone will not do, you need to configure StreamApi to filter the array and then iterate through it:

val args = arrayOf("1"."2"."3"."l"."q"."r") args.takeWhile { it ! ="q" }.forEach { print("$it ") }
println("The End")// 1 2 3 l The End
Copy the code