lambda表达式,称为匿名函数,是一种函数字面值,也就是没有声明的函数,但可以作为表达式传递出去.而已lambda表达式或者匿名函数作为函数参数的函数,就是高阶函数

一 函数类型的声明:

在kotlin中,声明一个函数类型的格式很简单,在kotlin中我们是通过->符号来组织参数类型和返回值类型,左右是函数的参数,右边是函数的返回值,函数的参数,必须在()中,多个参数的时候,用,将参数分开。如下:

//表示该函数类型,接收一个Int类型的参数,并且返回值为Int类型
 (Int)->Int
 
 //表示该函数类型,接收两个参数,一个Int类型的参数,一个String类型的参数,并且返回值为Int类型
 (Int,Stirng)->Int

那没有函数参数,和无返回值函数怎么声明?如下:

//声明一个没有参数,返回值是Int的函数类型,函数类型中,函数没有参数的时候,()不可以省略
 ()->Int
 
 //明一个没有参数,没有返回值的函数类型,函数类型中,函数没有返回值的时候,Unit不可以省略
 ()->Unit

接下来看看高阶函数参数里函数参数类型的表达:

//gaojiefun是一个高阶函数,因为他有一个函数类型的参数funParam,
 //注意这里有一个新的名词,函数类型,函数在kotlin中也是一种类型。
 //那他是什么类型的函数呢?注意(Int)->Int,这里表示这个函数是一个,
 //接收一个Int,并返回一个Int类型的参数。
 fun gaojiefun(funParam:(Int)->Int,param:Int){}

如果高阶函数里的参数也是高阶函数,那这个又如何表达呢?

private fun gaojiefun(funParams:((Int)->Int)->Int){}
 //这里表示的是一个高阶函数gaojiefun,他有一个函数类型的参数funParams。
 //而这个funParams的类型也是一个高阶函数的类型。funParams这个函数类型表示,
 //它接受一个普通函数类(Int)->Int的参数,并返回一个Int类型。这段话读起来
 //确实很绕,但是你明白了这个复杂的例子之后,基本所有的高阶函数你都能看懂什么意思了。

二 函数的传入

前面我们已经知道了高阶函数函数参数类型的声明,那我们再使用高阶函数的时候,如何传入呢?原始的方法就是创建一个函数,然后传入这个函数引用的方法,但是我们知道,Kotlin有很多语法糖,这里就用到了kotlin中的匿名函数和Lambda表达式

匿名函数
来讲匿名函数,看定义就知道这是一个没有名字的’函数’,注意这里的’函数’这两个字是带有引号的。首先来看看怎么在高阶函数中使用吧。

//接着上面的例子讲
//除了这种通过引用对象调用testHighFun(funObject)的方法,还可以直接把一个函数当做这个高阶函数的参数。

val param = fun (param:Int){ //注意这里是没有函数名的,所以是匿名'函数'
     //doSomeThing
 }
 gaojiefun(param)

注意:通过之前的分析,我们可以知道,这个高阶函数gaojiefun接收的参数是一个函数对象的引用,也就是说我们定义的val param是一个函数对象的引用,那么可以得出这个匿名’函数’ fun(param:Int){},他的本质是一个函数对象。他并不是’函数’。我们可以看一下反编译出来的java代码

//param是一个Function1类型的对象的引用
 Function1 param = (Function1)null.INSTANCE;
 this.gaojiefun(param);

所以重点记住,Kotlin中的匿名函数,它的本质不是函数。而是对象。它和函数不是一个东西,它是一个函数类型的对象。对象和函数,它们是两个东西。

Lambda表达式

Lambda 表达式的完整语法形式如下:
val sum: (Int, Int) -> Int = { x: Int, y: Int -> x + y }

Lambda 表达式总是括在花括号中, 完整语法形式的参数声明放在花括号内,并有可选的类型标注, 函数体跟在一个 -> 符号之后。如果推断出的该Lambda 的返回类型不是 Unit,那么该 Lambda 主体中的最后一个(或可能是单个) 表达式会视为返回值。

我们知道,Kotlin里是有支持类型推导的,所以上面的表达式我们是可以再次简化的:

val sum= { x: Int, y: Int -> x + y }
val sum: (Int, Int) -> Int = { x, y -> x + y }

在kotlin中还支持,如果函数的最后一个参数是函数,那么作为相应参数传入的 Lambda 表达式可以放在圆括号之外:

//比如我们上面的那个例子testHighFun,可以将lambda放到原括号之外
 gaojiefun(){
 //doSomeThing
 }
 
 //如果该 lambda 表达式是调用时唯一的参数,那么圆括号可以完全省略:如下
 gaojiefun{
 //doSomeThing
 }
 
 //一个 lambda 表达式只有一个参数是很常见的。
 //如果编译器自己可以识别出签名,也可以不用声明唯一的参数并忽略 ->。 该参数会隐式声明为 it: 如下
 gaojiefun{
     //doSomeThing
     it.toString(it)
 }

从 lambda 表达式中返回一个值

我们可以使用限定的返回语法从 lambda 显式返回一个值。 否则,将隐式返回最后一个表达式的值。参考官网的例子如下:

ints.filter {
     val shouldFilter = it > 0 
     shouldFilter
 }
 
 ints.filter {
     val shouldFilter = it > 0 
     return@filter shouldFilter
 }

好了,以上就是Lambda的基本用法了。

讲了这么多,我们只是讲解了Lambda怎么使用,那么它的本质是什么?其实仔细思考一下上面的testHighFun可以传入一个Lambda表达式就可以大概知道,Lambda的本质也是一个函数类型的对象。这一点也可以通过发编译的java代码去看。

三 匿名函数与Lambda表达式的总结:

  1. 两者都能作为高阶函数的参数进行传递。
  2. 两者的本质都是函数类型的对象。