<>前言

Kotlin的高阶函数与Lambda表达式是Kotlin的两大特色,使用频率非常高。熟悉它的用法与本质对于简化代码、提升开发效率非常有帮助。
这两个概念不是同一个东西,但是又有非常紧密的关联。这篇文章带你弄懂什么是高阶函数,以及Lambda表达式的本质和使用。

<>一、什么是高阶函数

高阶函数就是将函数类型用作参数或返回值的函数,例如:

<>函数类型当作参数
fun a(arg:(Int)->String):String{ arg(1) }
<>函数类型当作返回值
fun b(arg:(Int)->String):(Int)->Unit{ ... }
<>什么是函数类型

Kotlin 使用类似 (Int) -> String 的一系列函数类型来处理函数的声明。
例如onClick的赋值操作:

val onClick: (View) -> Unit = ……

其中(View) -> Unit就是一种函数类型。

<>二、在Java里如何将函数当作参数传给另一个函数

在Java里不能将函数当作参数传给另一个函数,但是有一个变通的方案,就是将函数包装成Interface。比如点击事件,将onClick函数包装成OnClickListener传递给View的setOnClickListener函数:
public interface OnClickListener{ void onClick(View view) } OnClickListener
onClickListener=new OnClickListener{ @Override public void onClick(View view){
doSomething(); } } view.setOnClickListener(onClickListener);
View的源码简化:
public class View{ OnClickListener mOnClickListener; public void
setOnClickListener(OnClickListener onClickListener){ this.mOnClickListener=
onClickListener} public void onTouchEvent(MotionEvent motionEvent){ ...
mOnClickListener.onClick(this); ... } }
<>三、在Kotlin里如何将函数当作参数传给另一个函数

先看这两个函数:
//定义一个参数为函数类型的函数(高阶函数) fun a(arg:(Int)->String):String{ arg(1) }
//定义一个接受Int返回String的函数 fun b(arg:Int):String{ return arg.toString() }
如何在调用a的时候将b作为实参传给a呢?首先要将函数b实例化变成对象才能传递。

<>(1)使用双冒号实例化函数
a(b) //错误写法,编译不通过。不能将函数本身直接传递。b没有实例化,不是对象 a(::b) //正确写法,将b用双冒号实例化再进行传递 val d=
::b //将b实例化赋值给d a(d) //正确写法,d已经是函数对象。
<>(2)使用匿名函数实例化函数

所谓匿名函数,就是没有名字的函数,比如
fun(arg:Int):String{ //跟正常函数比,没有函数名字 return arg.toString() }
匿名函数不是一个函数类型,它其实是函数实例(对象)。

继续看如何调用上面的高阶函数a:
//正确写法。调用a函数,传递一个匿名函数进去。 a(fun(arg:Int):String{ return arg.toString() })
//将匿名函数赋值给d val d=fun(arg:Int):String{ return arg.toString() } a(d)
//正确写法。d已经是匿名函数。
在kotlin里如何定义OnClickListener?
fun setOnClickListener(onClick:(View)->Unit){ this.onClick=onClick } view.
setOnClickListener(fun(v:View)->Unit){ doSomething() })
<>(3)、使用Lambda表达式实例化函数
view.setOnClickListener{ doSomething() }
<>四、Lambda表达式

Lambda表达式是匿名函数的简化形式。所以Lamdba表达式跟匿名函数一样,它不是一个函数类型,它是函数实例(对象)。

完整的lambda表达式示例:
{ x: Int, y: Int -> x + y }
其中“->”前面是参数列表,“->”后面是函数实现。

将上文示例中的setOnClickListener传递的匿名函数进行简化,写成Lambda表达式:
//不用lambda表达式,使用传递匿名函数: view.setOnClickListener(fun(v:View)->Unit){ doSomething
() }) //使用Lambda表达式的写法: view.setOnClickListener({v:View-> doSomething() })
<>Lambda表达式的特点

(1)、如果Lambda是函数的最后一个参数,可以将Lambda写在括号外面:
view.setOnClickListener(){v:View-> doSomething() }
(2)、如果Lambda是函数唯一的参数,还可以将括号去掉:
view.setOnClickListener{v:View-> doSomething() }
(3)、如果Lambda内部只有一个参数,可以省略掉不写:
view.setOnClickListener{ doSomething() }
需要使用这个省略的参数时,用it代表即可。
view.setOnClickListener{ doSomething() it.setVibility(View.GONE) }
(4)、Lambda表达式的返回值不能用return,只能使用最后一行代码表示返回值:
//编译报错 val d :(Int)->String = { return it.toString() //编译报错:return is not
allowed here } //正确 val d :(Int)->String = { it.toString() }
<>Lambda参数类型哪些情况下不能省略?

在上面的示例中,可以省略参数类型是因为setOnClickListener函数已经声明了参数类型,Lambda可以从上下文推断出来。而当我们将Lambda表达式赋值给一个变量时,不能省略参数类型,示例:
//正确,将匿名函数赋值给d val d = fun(arg:Int):String{ return arg.toString() }
//错误,不能省略参数类型 val d = { it.toString() //报错 }
在赋值操作时如果一定要省略Lambda表达式类型,必须给左边变量指明类型,示例:
//正确 ,在左边的变量指明类型 val d :(Int)->String = { it.toString() }
<>五、总结

在kotlin里,函数与类都是一等公民,函数也可以实例化作为参数传递给另一个函数,函数也可以当作函数的返回值。函数需要实例化变成对象才可以进行传递,使用双冒号、匿名函数、Lambda表达式都可以将函数实例化。

技术
下载桌面版
GitHub
百度网盘(提取码:draw)
Gitee
云服务器优惠
阿里云优惠券
腾讯云优惠券
华为云优惠券
站点信息
问题反馈
邮箱:ixiaoyang8@qq.com
QQ群:766591547
关注微信