A lambda expression is always surrounded by curly braces
// declaration
{ println("I am a function lambda! ") }
// store in a variable
val printer = { println("I am saved!") }
// invoke a stored lambda
run(printer)
// lambdas with parameters
val printMessage = { message: String -> print(message) }
// invoke it
printMessage("hello there!")
Higher Order Functions
A higher order function is a function that either accepts another function as a parameter, returns a function as its return value, or both
Function Types
This function has two parameters. The first is a string and the second is a function from String to String. The entire function returns Unit (void)
// declare a function which takes a lambda
fun foo(str: String, fn: (String) -> String): Unit {
val applied = fn(str)
println(applied)
}
// invoke it
foo("hello", { it.reversed() })
Type Inference
When you use a lambda as a parameter, if there’s only a single parameter, you don’t need to explicitly declare the lambda’s argument type.
If you store a lambda in a variable, there’s no context from which to infer the arg types, so you have to specify them explicitly.
// type inference
{ message -> println(message) }
// no type inference
val getAge = { p: Person -> p.age }
people.maxBy(getAge)
In Kotlin, unlike in Java you’re allowed to access non-final variables and modify them in a lambda.
Member References
You can have a reference to a function that’s declared at the top level and isn’t a member of a class. In this case you omit the class name and start with ::
fun salute() = println("Salute!")
run(::salute) Salute!
// you can store or postpone the action of creating an instance of a class using a constructor reference
data class Person(val name: String, val age: Int)
// constructor reference
val createPerson = ::Person
val p = createPerson("Alice", 29)
println(p)
Extension functions
You can also reference extension functions the same way as a member reference
fun Person.isAdult() = age >= 21
val predicate = Person::isAdult
Returning Functions from Functions
To declare a function that returns another function, you specify a function type as its return type.
This is less used but it’s used when you have a piece of logic in a program that can vary depending on hte state of the program or other conditions.
// declaration
fun bar(): (String) -> String = { str -> str.reversed() }
// invoke
val rev = bar()
rev("hello!")