学习
实践
活动
专区
工具
TVP
写文章

Kotlin实战之Fuel的高阶函数

Fuel 是一个用 Kotlin 写的网络库,与 OkHttp 相比较,它的代码结构比较简单,但是它的巧妙之处在于充分利用了 Kotlin 的语言特性,所以代码看上去干净利落。

OkHttp 使用了一个interceptor chain来实现拦截器的串联调用,由于 Java 语言( JDK ≤ 7)本身的局限性,所以实现代码比较臃肿,可读性也不友好。当然,RxJava 再加上 retrolambda 这种 backport 的出现,一定程度上了缓解了这种尴尬,但是 Kotlin 天生具备的声明式写法又使得 Java 逊色了很多。

我们知道,拦截器本质上是一个责任链模式(chain of responsibility)的实现,我们通过具体代码来学习一下 Kotlin 究竟是如何利用高阶函数实现了拦截器功能。

首先定义一个 用于存储拦截器实例:

注意,Kotlin 的类型系统明确区分了 mutable 和 immutable,默认的 List 类型是 immutable。

的元素类型是一个高阶函数:

作为元素类型的高阶函数,其参数也是一个高阶函数 , 同时,返回值也是高阶函数 。

然后,我们给 定义一个增加元素的方法:

的参数类型

与 的元素类型一致。

注意,这里又出现了一个 Kotlin 有而 Java 没有的语言特性:操作符重载。

我们没有调用 ,而是用了一个 的操作符 (MutableCollections.kt 中定义的操作符重载):

那么,此时应该定义一个拦截器的函数实例了:

是一个函数,它的返回值是一个 lambda 表达式(即高阶函数):

1) 这个 lambda 的参数是 (参数名是 ,参数类型是 ),返回值是另一个 lambda 表达式:

2) 因为 lambda 本身是一个函数字面量(function literal),它的类型通过函数本身可以推到得出,如果我们用一个变量来引用这个 lambda 的话,变量的类型是 。

由1、2两点可知, 的返回值是一个 lambda 表达式,它的参数是 ,返回值也是 。

这里的泛型函数略抽象,我们来看一个具体化的函数:

同理, 函数的参数为 、返回值为 。

拦截器都定义好了,那么应该如何调用呢?Kotlin 一行代码搞定::

是 的一个扩展函数,先来看声明:

函数功能总结为一句话:从右往左,对列表中的每一个元素执行 操作,每个操作的结果是下一次操作的入参,第一次 的初始值是 。

回头来看拦截器列表 如何执行了 :

参数 的实参是 ,一个函数字面量,没有执行任何操作,接收 返回 。

参数 可接收一个 lambda,所以它的实参 可以位于圆括号之外。 的泛型是 ,具体类型是

的类型通过 的实参 可以推到得出—— 。

OK,语法完全没毛病,再来看语义。

至此,一个简单的拦截器功能就实现了,代码竟然如此简洁,感动!

参考

拆轮子系列:拆 OkHttp by Piasy

Kotlin中文文档

  • 发表于:
  • 原文链接http://kuaibao.qq.com/s/20180410G1VGZ700?refer=cp_1026
  • 腾讯「腾讯云开发者社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。

关注

腾讯云开发者公众号
10元无门槛代金券
洞察腾讯核心技术
剖析业界实践案例
腾讯云开发者公众号二维码

扫码关注腾讯云开发者

领取腾讯云代金券