前言
主要用来介绍Lambda表达式的使用,以及它所精简的代码。
什么是Lambda
Lambda 其实是一个匿名函数,即没有函数名的函数。
它是基于数学中的λ演算 得名。之后各种开发语言分别引入了Lambda表达式的支持。例如C#,Java,C++,Python,Kotlin等等。
Lambda 与Kotlin
Kotlin从一开始,就支持Lambda表达式。
我们说过,Lambda表达式,就是一个匿名函数
在Kotlin中,将这种通过Lambda精简的匿名函数,称为高阶函数。
其实Lambda可以当一种表达式的写法规则而已。
实例:
val sum: (Int, Int) -> Int = { x: Int, y: Int -> x + y }
这是一个比较典型的lambda 表达式。其中花括号里面的内容才是Lambda表达式。
定义:Lambda表达式总是在花括号里面。完整语法形式的参数声明,都放在花括号内,并有可选的类型标注,函数体跟在 ->
符号之后。该Lambda主体中的最后一个表达式会视为返回值。
上面的句子,我们还可以精简为:
val sum1 = { x: Int, y: Int -> x + y }
两者是等价的。这是基于kotlin 的特性进行的精简
在Kotlin之中,有一个约定: 如果函数的最后一个参数是函数,那么作为相应参数传入的Lambda表达式可以放在()
之外:
val product = items.fold(1) { acc, e -> acc * e }
这种语法叫做 :拖尾lambda表达式
实例1:
//定义了一个函数,比较了两个传参
fun test1(i1: Int, i2: Int) = i1 > i2
fun main(array: Array<String>) {
val s = test1(12, 10)
println(s)
//Lambda 表达式 实现 和test1没有关系了。我们这是创建了一个新的函数
var lambda = { i1: Int, i2: Int -> i1 > i2 }
println(lambda(12, 10))
}
//输出:
true
true
如果在lambda的返回参数之中添加更多的语句。那么最后一个表达式的值就是Lambda的值
实例2:
fun main(array: Array<String>) {
val sum = { x: Int, y: Int ->
println("接口将会返回$x+$y 的和")
x + y
}
println(sum(1, 2))
}
//输出:
//接口将会返回1+2 的和
//3
实例3:
//实例 --创建一个数组
var ss = arrayListOf("ssa", "sda", "ad")
//利用 filter函数 筛选数组满足Lambda 表达式的结果。
var sss = ss.filter {
//传参值 不等于ssa的数据
!it.equals("ssa")
}
//得到结果
println(sss)
//输出:
[sda, ad]
实例4: 我们自己创建一个
//我们有一个人的对象。
class People(var name: String, var age: Int, var six: Int) {
//它这个传参,就是一个高阶函数的实现。
inline fun trunOut(predicate: (People) -> Boolean): Boolean {
return predicate(this)
}
}
fun main(array: Array<String>) {
var people = People("Z同学", 18, 1)
val jieguo = people.trunOut {
it.age > 20 && it.six == 0
}
println(jieguo)
}
it 单个参数的隐式名称
一个lambda表达式中如果只有一个传参。那么可以直接用it
来指代。
并且忽略->
符号
实例1:
ints.filter { it > 0 } // 这个Lambda表达式: {it :Int -> it> 0 }
我们使用it之后,编译器会自动帮我们替换成指定传参
实例2:
class People {
var age = 10;
fun maxBy(str: (People) -> Int) {
println("得到的值是: $str")
}
}
fun main(array: Array<String>) {
val people = People()
//第一种 全部数据输入情况下
people.maxBy({ p: People -> p.age })
//第二种Kotlin 约定 这种情况下可以将Lombda表达式放在括号外
people.maxBy() { p: People -> p.age }
//第三种 在编译器能够推导数据格式时,我们可以省略格式
people.maxBy { p -> p.age }
//第四种,当编译器能够推导数据格式,并且传参只有一个的时候。
people.maxBy { it.age }
//但是这种情况下的Lambda 不能抽象
val sum = { x: Int -> x > 10 }
//不能这样简写,因为编译器无法根据上下文确定x的参数类型
val sum1 = { x -> x > 10 }
}
下划线用于未使用的变量-(Kotlin 1.1版本开始)
如果lambda表达式的参数未使用,那么可以用下划线取代名称:
map.forEach { _,value -> println($value!)}
实例1:
//我们有一个人的对象。
class People(var name: String, var age: Int) {
/**
* 定义一个函数
*/
fun test1(lmdd: (String, Int) -> String): String {
return lmdd(name, age)
}
}
fun main(array: Array<String>) {
var people = People("Z同学", 18)
var temp = people.test1 { _, i ->
var s = ""
when {
i < 5 -> {
s = "幼儿"
}
i < 16 -> {
s = "未成年"
}
i > 60 -> {
s = "老年人"
}
else -> {
s = "成年人"
}
}
s
}
println(temp)
}
//输出
成年人
带接收者的Lambda表达式
表达式形式: A.() -> C
优势:在lambda函数体可以无需任何额外的限定符的情况下,直接使用接收者对象的成员(属性和函数),也可以使用this访问接收者对象。
在Kotlin的标准库中,有提供了带接收者的lambda表达式: with
和apply
Kotlin源码样式:
@kotlin.internal.InlineOnly
public inline fun <T, R> with(receiver: T, block: T.() -> R): R {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
return receiver.block()
}
@kotlin.internal.InlineOnly
public inline fun <T> T.apply(block: T.() -> Unit): T {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
block()
return this
}
实例1:
class Test() {
fun test() {
println("打印数据参数")
}
}
fun demo1(tt: Test.() -> Unit): Test {
val temp = Test()// 创建一个接收者对象
temp.tt() //将接收者对象传给tt Lambda
return temp
}
fun main(array: Array<String>) {
var te = demo1 {
test()
}
te.test()
}
//输出
打印数据参数
打印数据参数
闭包
Kotlin之中支持函数中包含函数。
//这个函数,定义了返回值是一个高阶函数,
fun test(a: Int): () -> Int {
var b = 3
return fun(): Int {
b++
return a + b
}
}
fun main(array: Array<String>) {
var ss = test(1)
println(ss) //这个时候 ss 是一个函数对象,所以直接打印会打印内存地址
println(ss()) //执行了这个Lambda表达式
println(ss()) //执行了这个Lambda表达式
println(ss()) //执行了这个Lambda表达式
}
输出结果:
Function0<java.lang.Integer>
5
6
7
评论区