- 一、Lambda 介绍
- 二、Lambda 使用
- 三、Lambda 实践
- 1. 如何使用 it
- 2. 如何使用下划线(_)
- 3. 如何使用匿名函数
- 4. 实例
Lambda 表达式的本质其实是匿名函数,因为在其底层实现中还是通过匿名函数来实现的。但是我们在用的时候不必关心其底层实现。不过 Lambda 的出现确实是减少了代码量的编写,同时也使代码变得更加简洁明了。 Lambda 作为函数式编程的基础,其语法也是相当简单的。
应用场景:
- 当一个事件发生的时候运行这个事件处理器
- 把这个操作应用到这个数据结构中所有的元素上
2.1 Lambda 表达式的特点
- Lambda 表达式总是被大括号括着
- 其参数(如果存在)在符号’->'之前声明(参数类型可以省略)
- 函数体(如果存在)在符号’->'后面。
2.2 Lambda 语法
- 无参数的情况 : val/var 变量名 = { 操作的代码 }
- 有参数的情况 val/var 变量名 : (参数的类型,参数类型,…) -> 返回值类型 = {参数1,参数2,… -> 操作参数的代码 } 可等价于 //此种写法:即表达式的返回值类型会根据操作的代码自推导出来。 val/var 变量名 = { 参数1 : 类型,参数2 : 类型, … -> 操作参数的代码 }
- lambda表达式作为函数中的参数的时候,这里举一个例子: fun test(a : Int, 参数名 : (参数1 : 类型,参数2 : 类型, … ) -> 表达式返回类型){ … }
- 实例一:无参数的情况
// 源代码
fun test(){ println("无参数") }
// lambda代码
val test = { println("无参数") }
// 调用
test() => 结果为:无参数
- 实例二:有参数的情况
// 源代码
fun test(a : Int , b : Int) : Int{
return a + b
}
// lambdaval
test : (Int , Int) -> Int = {a , b -> a + b}
// 或者
val test = {a : Int , b : Int -> a + b}
// 调用
test(3,5) => 结果为:8
- 实例三:lambda 表达式作为函数中的参数的时候
// 源代码
fun test(a : Int , b : Int) : Int{
return a + b
}
fun sum(num1 : Int , num2 : Int) : Int{
return num1 + num2
}
// 调用
test(10,sum(3,5)) // 结果为:18
// lambdafun
test(a : Int , b : (num1 : Int , num2 : Int) -> Int) : Int{
return a + b.invoke(3,5)
}
// 调用
test(10,{ num1: Int, num2: Int -> num1 + num2 }) // 结果为:18
2.3 小结
-
lambda 表达式总是被大括号括着。
-
定义完整的 Lambda 表达式如上面实例中的语法2,它有其完整的参数类型标注,与表达式返回值。当我们把一些类型标注省略的情况下,就如上面实例中的语法2的另外一种类型。当它推断出的返回值类型不为’Unit’时,它的返回值即为->符号后面代码的最后一个(或只有一个)表达式的类型。
-
在上面例子中语法3的情况表示为:高阶函数,当Lambda表达式作为其一个参数时,只为其表达式提供了参数类型与返回类型,所以,我们在调用此高阶函数的时候我们要为该Lambda表达式写出它的具体实现。
-
invoke()函数:表示为通过函数变量调用自身,因为上面例子中的变量 b 是一个匿名函数。
- it 并不是 Kotlin 中的关键字,也不是保留字;
- it 是在当一个高阶方法中 Lambda 表达式的参数只有一个的时候可以使用 it 来使用该参数;
- it 可表示为单个参数的隐式名称,是 Kotlin 语言约定的
实例:使用隐形参数 it
fun test(num1 : Int, bool : (Int) -> Boolean) : Int{
return if (bool(num1)){ num1 } else 0
}
println(test(10,{it > 5}))
println(test(4,{it > 5}))
输出结果:
10 0
2. 如何使用下划线(_)在使用 Lambda 表达式的时候,可以用下划线 (_) 表示未使用的参数,表示不处理这个参数。
val map = mapOf("key1" to "value1","key2" to "value2","key3" to "value3")
map.forEach{
key , value -> println("$key \t $value")
}
// 不需要key的时候
map.forEach{
_ , value -> println("$value")
}
输出结果:
key1 value1 key2 value2 key3 value3 value1 value2 value3
3. 如何使用匿名函数- 匿名函数的特点是可以明确指定其返回值类型。
- 它和常规函数的定义几乎相似。他们的区别在于,匿名函数没有函数名。
// 当返回值可以自动推断出来的时候,可以省略,和函数一样
val test1 = fun(x : Int , y : Int) = x + y
val test2 = fun(x : Int , y : Int) : Int = x + y
val test3 = fun(x : Int , y : Int) : Int{
return x + y
}
println(test1(3,5))
println(test2(4,6))
println(test3(5,7))
输出结果:
8 10 12
4. 实例在 Android 开发中为 RecyclerView 的适配器编写一个 Item 点击事件:
class TestAdapter(val context : Context , val data: MutableList)
: RecyclerView.Adapter(){
private var mListener : ((Int , String) -> Unit)? = null
override fun onBindViewHolder(holder: TestViewHolder?, position: Int) {
...
holder?.itemView?.setOnClickListener {
mListener?.invoke(position, data[position])
}
}
override fun onCreateViewHolder(parent: ViewGroup?, viewType: Int): TestViewHolder {
return TestViewHolder(View.inflate(context,layoutId,parent))
}
override fun getItemCount(): Int {
return data.size
}
fun setOnItemClickListener(mListener : (position : Int, item : String) -> Unit){
this.mListener = mListener
}
inner class TestViewHolder(itemView : View) : RecyclerView.ViewHolder(itemView)
}
// 调用
TestAdapter(this,dataList).setOnItemClickListener { position, item ->
Toast.makeText(this,"$position \t $item",Toast.LENGTH_SHORT).show()
}