不管有没有用过 Kotlin,不少人应该听过一个词,叫函数式编程
,简单来说在函数式编程
语言里,函数可以作为别的函数的参数、函数的返回值「参数或返回值为函数的函数也被称为高阶函数
,仅仅是个概念,了解就行」值给变量或存储在数据结构中。在这样的语言中,函数的名字没有特殊含义,它们被当作具有函数类型
的普通的变量对待。
Kotlin 语言支持函数式编程
,为促成这点,作为一门静态类型编程语言的 Kotlin 使用一系列函数类型来表示函数并提供一组特定的语言结构,例如 lambda 表达式
。
函数类型
因为 Kotlin 支持函数作为参数或返回值,那意味着函数类型与其他类型一样(如:List
、String
),它们一样可以被声明、初始化等等。比如我们声明并初始化一个List
,我们是这样写的:
val list: List = ArrayList()
= 左边是定义变量类型,右边是初始化赋值。这很简单,学过任何编程语言的应该都能看得懂。那函数类型
是如何声明与初始化?我们来看看。
函数类型声明
Kotlin 使用类似(类型) -> 类型
的结构来声明函数类型,以->
为分割符,左边是函数参数列表及类型,右边是函数返回类型。
- 所有函数类型都有一个圆括号括起来的参数类型列表以及一个返回类型:
(A, B) -> C
表示接受类型分别为A
与B
两个参数并返回一个C
类型值的函数类型。 参数类型列表可以为空,如() -> A
。Unit
返回类型不可省略。 - 函数类型可以有一个额外的_接收者_类型,它在表示法中的点之前指定: 类型
A.(B) -> C
表示可以在A
的接收者对象上以一个B
类型参数来调用并返回一个C
类型值的函数。 带有接收者的函数字面值通常与这些类型一起使用。 - 挂起函数属于特殊种类的函数类型,它的表示法中有一个 suspend 修饰符 ,例如
suspend () -> Unit
或者suspend A.(B) -> C
。
如需将函数类型指定为可空,请使用圆括号:
((Int, Int) -> Int)?
。函数类型可以使用圆括号进行接合:
(Int) -> ((Int) -> Unit)
箭头表示法是右结合的,
(Int) -> (Int) -> Unit
与前述示例等价,但不等于((Int) -> (Int)) -> Unit
。
函数类型实例化
有几种方法可以获得函数类型的实例
使用函数字面值的代码块
-
lambda 表达式:
{ a, b -> a + b }
-
匿名函数
fun(s: String): Int { return s.toIntOrNull() ?: 0 }
lambda 与匿名函数都可以用来实例化函数类型,它们可以相互转换,大多数情况是完全等价的。
// Lambda 表达式
val fun1: (Int) -> Unit = { p: Int -> }
// 匿名函数
val fun2: (Int) -> Unit = fun (p: Int) { }
这两种写法是完全等价的,Lambda 表达式可以被视为是匿名函数的简单写法,并且它还可以更简单。
- 可以省略参数类型
- 如果参数只有一个,那这个参数也可以省略,lambda 有一个默认参数名
it
上面的 Lambda 可以写成这样:val fun1: (Int) -> Unit = { }
大部分接触 Kotlin 的程序员都是从 Java 过来的,Java 里面我们都知道匿名类
,没听过有匿名函数
。
class AnonymousType{ }
public static void main(String[] args) {
// 实例化 AnonymousType
AnonymousType a = new AnonymousType();
// 后面加花括号之后它就不是 AnonymousType 类型了,而是 AnonymousType 的子类
// 且这个子类是没有显示名称的,
// 最常见使用匿名类的场景就是,当声明类型是接口、抽象类时,不想显示声明接口、抽象类
// 的子类,所以会实例化一个匿名类类型
AnonymousType a2 = new AnonymousType(){};
}
而匿名函数
与匿名类
是比较相似的,刚从 Java 过来,不了解 Kotlin 的函数类型,所以更不了解匿名函数
。但实际上它们本质上是一样的,使用场景都是声明某个类型(函数类型),但又不想显示声明某个函数,所以便使用了匿名函数
。
如果你把 Kotlin 的代码 decode 成 Java,那你会惊喜的发现,本质上函数类型对应的就是一个接口,初始化的时候使用的就是匿名类。
使用已有声明的可调用引用
-
顶层、局部、成员、扩展函数:
::isOdd
、String::toInt
, -
顶层、成员、扩展属性:
List<Int>::size
, -
构造函数:
::Regex
这包括指向特定实例成员的绑定的可调用引用:foo::toString
。
Kotlin 可以用双冒号"::
"表示对方法、属性的引用。举个例子,可能有人刚接触 lambda 、匿名函数感觉还是会陌生,那么用::
引用函数(Java 中称为方法,Kotlin叫函数,本质都一样,没区别)会让你更熟悉些,这种方式相当于是实例化了一个匿名函数。
// 方法引用
val fun3: (Int) -> Unit = ::func1
fun func1(p: Int) { }
这种方式跟上述的两种函数实例化也是一样的,完全等价。如果你刚开始 lambda 不习惯,也可以使用这样的方式。fun1
就是一个普通方法,如果这个方法的参数与返回类型与声明的函数类型一致,那它就可以被引用来实例化定义的函数。
总结
这就总结了吗?貌似主要讲的是 Kotlin 的函数类型呀?
是的 lambda
就是实例化函数类型的一种方式。Kotlin 语言里函数能够作为函数的参数、返回值类型的本质原因是 Kotlin 有函数类型
这个类型。而 lambda
是实例化函数类型的一种方式,它与匿名函数
、函数引用
作用本质上是一样的,区别是 lambda
在使用上更简单、方便。
在大多数情况下,lambda
可以视为是匿名函数
的一种更简单写法,你如果不习惯这种看不到参数数据类型的写法,也可以使用匿名函数
,它们是一样的。
完。
最后
如果想要成为架构师或想突破20~30K薪资范畴,那就不要局限在编码,业务,要会选型、扩展,提升编程思维。此外,良好的职业规划也很重要,学习的习惯很重要,但是最重要的还是要能持之以恒,任何不能坚持落实的计划都是空谈。
如果你没有方向,这里给大家分享一套由阿里高级架构师编写的《Android八大模块进阶笔记》,帮大家将杂乱、零散、碎片化的知识进行体系化的整理,让大家系统而高效地掌握Android开发的各个知识点。
相对于我们平时看的碎片化内容,这份笔记的知识点更系统化,更容易理解和记忆,是严格按照知识体系编排的。
全套视频资料:
一、面试合集
二、源码解析合集
三、开源框架合集
欢迎大家一键三连支持,若需要文中资料,直接点击文末CSDN官方认证微信卡片免费领取↓↓↓
![](https://i-blog.csdnimg.cn/blog_migrate/0ba0fd76a04d3e935cdc231b3f2b1a66.png)