什么是高阶函数?
高阶函数是将函数作为参数或者返回值的函数。
-
特点
- 参数可以是函数
- 返回值可以是函数
- 所有函数类型都有一个圆括号括起来的参数类型列表及一个返回类型
-
举个🌰
var onClick:()->Util //onClick变量类型为:无参且无返回类型的函数 var onClick:(A,B)->C //onCick变量类型为:参数类型分别为A,B,返回类型为C的函数 (x:Int,y:Int) //函数类型可以选择性包含函数的参数名,用于表明参数含义 ((Int,Int)->Util)? //如果函数类型可为空,要使用圆括号后加?
上述就是一个高阶函数用法,定义某个变量的类型为函数,
注意:
- 参数类型可以为空
()
Unit
返回类型不可省略
- 参数类型可以为空
-
函数类型实例调用
函数类型的值可以通过其
invoke(...)
操作符调用:f.invoke(x)
或者直接f(x)
Lambda 表达式
-
简述
- lambda 表达式总是被大括号括着,
- 其参数(如果有的话)在
—>
之前声明(参数类型可以省略), - 函数体(如果存在的话)在
—>
后面。 - lambda隐式返回最后一个表达式的值(或者使用
限定的返回
语法显示返回一个值)
-
语法
val sum:(Int,Int)->Int={ x:Int,y:Int->x+y}
在 Kotlin 中有一个约定,如果函数的最后一个参数是一个函数,并且你传递一个 lambda 表达式作为相应的参数,你可以在圆括号之外指定它:
比如map函数
//map函数最后一个参数是一个函数
fun <T, R> List<T>.map(transform: (T) -> R): List<R> {
val result = arrayListOf<R>()
for (item in this)
result.add(transform(item))
return result
}
//使用
val dataList = list.map{it—>
it*2
}
使用Kotlin高阶函数实现接口回调
在学习使用Kotlin高阶函数实现接口回调之前,先看看我们在Java中接口回调通常使用方法
Java中接口使用
-
普通使用
定义接口
public interface ICallback { void nextFun(String message); void errorFun(int code, String message); }
业务中使用
public class LoginLogicImpl { //声明login方法,参数为ICallback回调接口类型 public void login(ICallback callback) { //TODO... if (true) { callback.nextFun("success"); } else { callback.errorFun(404, "not found page"); } } }
外部调用(通过匿名内实现接口的回调)
public class LoginLogicPresenter { LoginLogicImpl loginLogic = new LoginLogicImpl(); public void login() { loginLogic = new LoginLogicImpl(); /** *调用LoginLogicImpl的login方法,通过new ICallback()匿名类方式实现接口回调。 *必须显示声明所有接口中的回调方法。 */ loginLogic.login(new ICallback() { @Override public void nextFun(String message) { Log.d(TAG,"message->" + message) } @Override public void errorFun(int code, String message) { Log.e(TAG,"code->" + code + "message->" + message) } }); } }
如上我们在使用该接口时候,需要显示的声明接口内所有的回调方法,如果不需要显示声明所有借口回调方法怎么办呢? 那么我们可以通过提供一个该接口的实现类来达到需求,具体实现如下
-
简单使用
声明接口的实现类
public class CallbackImpl implements ICallback { @Override public void nextFun(String message) { } @Override public void errorFun(int code, String message) { } }
业务中使用
public class LoginLogicImpl { //声明函数,参数为回调接口的实现类 public void register(CallbackImpl callbackImpl){ //TODO... if(true){ callbackImpl.nextFun("success"); }else{ callbackImpl.errorFun(404,"not found page"); } } }
外部调用
public class LoginLogicPresenter { LoginLogicImpl loginLogic = new LoginLogicImpl(); public void register() { /** *调用LoginLogicImpl的register方法,通过new CallbackImpl()匿名类 *实现回调(可选择性的显示声明接口内回调方法) */ loginLogic.register(new CallbackImpl() { @Override public void nextFun(String message) { super.nextFun(message); Log.d(TAG,"success->" + message); } //@Override 可根据需要选择性的显示回调方法 //public void errorFun(int code, String message) { // super.errorFun(code, message); //} }); } }
Kotlin中接口使用
在kotlin中如果我们按照Java的思想进行接口开发使用,大概会有如下实现
-
Kotlin中接口普通使用
定义接口
interface ICallback { fun nextFun(message: String) fun errorFun(code: Int, message: String) }
业务中使用
object LoginLogicImpl { //声明login方法,参数为:ICallback回调接口类型 fun login( callback: ICallback) { //todo... if (true) { callback.nextFun("success") } else { callback.errorFun(400, "failure...") } } }
外部使用(使用
object对象表达式
,类似于java中的匿名类
)class LoginLogicPresenter { fun login() { /** *调用LoginLogicImpl的login方法,使用object对象表达式实现接口回调(必须要显示声明接口中 *全部回调方法) */ LoginLogicImpl.login(object : ICallback { override fun nextFun(message: String) { println("success->$message") } override fun errorFun(code: Int, message: String) { println("failure->$code,$message") } }) } }
上面就是我们在kotlin中通过java思想实现的接口,使用了object对象表达式(类似Java中匿名类) 实现回调。
在我们使用Android系统提供的View的
setOnClickListener
方法时候,我们发现其除了提供object
对象表达式方式之外,还提供了setOnClickListener(it->)
方法,如下button.setOnClickListener(object :View.OnClickListener{ override fun onClick(v: View?) { //TODO } })
button.setOnClickListener {it-> //TODO }
可见后者并没有使用
object
对象表达式,而是通过kotlin的高阶函数
和Lambda
表达式实现。那么我们是不是也可以将我们之前的接口更改为此种方式呢?当然可以!!如下: -
使用Kotlin高级函数和Lambda优化接口回调
-
定义接口:声明回调函数
/** *定义回调接口 */ interface IResponseCallback<T> { fun nextFun(data: T?) fun errorFun(code: Int, message: String) }
-
定义接口实现类:声明函数类型变量和对外提供的回调方法(与接口回调功能保持一致),并实现接口内回调方法
-
声明函数类型变量(参数与接口回调函数一致)
class ResponseCallbackListener<T> : IResponseCallback<T> { //通过高阶函数声明函数类型变量(参数与接口互调函数一致) lateinit var next: (data: T?) -> Unit lateinit var error: (code: Int, message: String) -> Unit }
-
声明回调方法(要与接口提供回调功能一致)
class ResponseCallbackListener<T> : IResponseCallback<T> { //通过高阶函数声明函数类型变量(参数与接口互调函数一致) lateinit var next: (data: T?) -> Unit lateinit var error: (code: Int, message: String) -> Unit //声明回调方法(与接口回调功能一致),参数为对应的函数类型变量 fun OnNext(nextListener: (data: T?) -> Unit) { this.next = nextListener } fun OnError(errorListener: (code: Int, message: String) -> Unit) { this.error = errorListener } }
-
实现接口内回调方法
class ResponseCallbackListener<T> : IResponseCallback<T> { //通过高阶函数声明函数类型变量(参数与接口互调函数一致) lateinit var next: (data: T?) -> Unit lateinit var error: (code: Int, message: String) -> Unit //声明回调方法(与接口回调功能一致),参数为对应的函数类型变量 fun OnNext(nextListener: (data: T?) -> Unit) { this.next = nextListener } fun OnError(errorListener: (code: Int, message: String) -> Unit) { this.error = errorListener } //实现接口内回调方法,调用对应函数变量的invoke(param)方法实现回调 override fun nextFun(data: T?) { //函数类型的值可以通过其 invoke(……) 操作符调用:f.invoke(x) 或者直接 f(x)。 this.next.invoke(data) //this.next(data) } override fun errorFun(code: Int, message: String) { this.error.invoke(code, message) } }
-
-
-
使用
业务中使用
object LoginLogicImpl { //声明register方法,参数为:函数类型 fun register(callback: CallbackListenerImpl.() -> Unit) { var callBack = CallbackListenerImpl() //实例化回调接口实现类 callBack.callback() //将参数内的回调函数与实例化对象绑定 if (true) { callBack.nextFun("success") //成功回调 } else { callBack.errorFun(400, "failure...") //失败回调 } } }
外部调用
class LoginLogicPresenter { fun register() { //调用LoginLogicImpl的register方法(可选择性显示声明回调方法) LoginLogicImpl.register { OnNext { println("OnNext->$it") } //OnError { code, message -> // println("OnError->$code,$message") //} } } }
上面使用Kotlin的高阶函数以及Lambda表达式对普通的接口回调进行优化,并没使用
object对象表达式
实现了接口回调,并且不需要显示声明接口提供的所有回调方法,而是选择性的声明所需的回调方法即可。
更多Kotlin高阶函数及Lambda表达式学习地址参见《Kotlin中文社区》