这里写目录标题
本质
一段代码封装成 匿名函数
特点
- lambda 表达式必须通过 {} 来包裹
- 如果 lambda 声明了参数部分的类型,且返回值支持类型推导,则 lambda 表达式变量就可以省略函数类型声明
- 如果 lambda 变量声明了函数类型,那么 lambda 表达式的参数部分的类型就可以省略
- 如果 lambda 表达式返回的不是 Unit 类型,则默认最后一行表达式的值类型就是返回值类型
简写
- 如果一个函数的最后一个实参是lambda表达式,可以把lambda表达式提到小括号外边
- 如果lambda是函数的唯一实参是,小括号可以直接省略
- kotlin可以推导出的参数类型可以省略
- kotlin中可以使用it默认参数名代替参数名称
语法
- 完整语法:val sum: (Int, Int) -> Int = {x: Int, y: Int -> x + y}
- 简写1:val sum: (Int, Int) -> Int = {x, y -> x + y}
- 简写2:val sum={x:Int, y:Int -> x+y}
完整语法说明: 函数类型 -> Lambda表达式
函数类型:(Int, Int) -> Int
lambda表达式: {x: Int, y: Int -> x + y}
完整Lambda表达式说明:{参数1:参数类型,参数2: 参数类型 -> 函数体}
1、无参数的情况
val/var 变量名 = { 操作的代码 }
val test = { println("无参数") }
2、有参数的情况
val/var 变量名 : (参数的类型,参数类型,...) -> 返回值类型
= {参数1,参数2,... -> 操作参数的代码 }
val sum: (Int, Int) -> Int = {x, y -> x + y}
val/var 变量名 = { 参数1 : 类型,参数2 : 类型, ... ->
操作参数的代码 }
val sum={x:Int, y:Int -> x+y}
3、lambda表达式作为函数中的参数的时候
fun test(a : Int, 参数名 : (参数1 : 类型,参数2 : 类型, ... )
-> 表达式返回类型){
...
}
fun test(a : Int , b : (num1 : Int , num2 : Int) -> Int) : Int{
return a + b.invoke(3,5)
}
函数类型
函数变量的类型统称函数类型,函数类型就是声明该函数的参数类型列表和函数返回值类型
函数类型语法:(参数)->返回值类型
简单的函数类型
//无参、无返回值的函数类型(Unit 返回类型不可省略)
() -> Unit
//接收T类型参数、无返回值的函数类型
(T) -> Unit
//接收T类型和A类型参数、无返回值的函数类型(多个参数同理)
(T,A) -> Unit
//接收T类型参数,并且返回R类型值的函数类型
(T) -> R
//接收T类型和A类型参数、并且返回R类型值的函数类型(多个参数同理)
(T,A) -> R
复杂的函数类型
(T,(A,B) -> C) -> R
函数 和 lambda表达式
1、fun 在没有等号、只有花括号的情况下,就是代码块函数体,如果返回值非 Unit,必须带 return
fun foo(x: Int) {
print(x)
}
fun foo(x: Int, y: Int): Int {
return x + y
}
2、fun 带有等号,没有花括号,是单表达式函数体,可以省略 return
fun foo(x: Int, y: Int) = x + y
3、不管是用 val 还是 fun 声明,如果是等号加花括号的语法,就是声明一个 lambda 表达式
val foo = { x: Int, y: Int ->
x + y
}
// 调用方式: foo.invoke(1, 2) 或者 foo(1, 2)
fun foo(x: Int) = { y: Int ->
x + y
}
// 调用方式: foo(1).invoke(2) 或者 foo(1)(2)
4、lambda 表达式自调用
{x: Int, y: Int -> x + y}(1, 2)
Lambda之it
- it并不是Kotlin中的一个关键字(保留字)
- it是在当一个高阶函数中Lambda表达式的参数只有一个的时候可以使用it来使用此参数。it可表示为单个参数的隐式名称,是Kotlin语言约定的
示例1:遍历集合
// 这里举例一个语言自带的一个高阶函数filter,
//此函数的作用是过滤掉不满足条件的值。
val arr = arrayOf(1,3,5,7,9)
// 过滤掉数组中元素小于5的元素,取其第一个打印。
// 这里的it就表示每一个元素。
println(arr.filter { it < 5 }.component1())
示例2:
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}))
Lambda之下划线(_)
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")
}
带接收者的函数字面值
指定的接受者对象调用Lambda表达式的功能
要用Lambda表达式作为接收者类型的前提是接收者类型可以从上下文中推断出来
class HTML {
fun body() {
println("HTML.body() >>>")
}
fun go(){
println("HTML.go() >>>")
}
}
fun html(init:HTML.()->Unit):HTML{
val html=HTML()// 创建接收者对象
html.init()// 将该接收者对象传给该 lambda
return html
}
//调用
html { body() }
html { go() } // 调用该接收者对象的一个方法
实战: RecyclerView的适配器编写一个Item点击事件
class TestAdapter(val context : Context , val data: MutableList<String>)
: RecyclerView.Adapter<TestAdapter.TestViewHolder>(){
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()
}