Kotlin 核心编程 (24):基础语法 2.3.2

阅读数:1 2019 年 12 月 25 日 15:33

Kotlin核心编程(24):基础语法 2.3.2

(实例:函数作为参数的需求)

内容简介
本书不是一本简单介绍 Kotlin 语法应用的图书,而是一部专注于帮助读者深入理解 Kotlin 的设计理念,指导读者实现 Kotlin 高层次开发的实战型著作。书中深入介绍了 Kotlin 的核心语言特性、设计模式、函数式编程、异步开发等内容,并以 Android 和 Web 两个平台为背景,演示了 Kotlin 的实战应用。
全书共 13 章,分为 4 个部分:
热身篇—Kotlin 基础(第 1~2 章),简单介绍了 Kotlin 设计哲学、生态及基础语法,其中包括 Kotlin 与 Scala、Java 之间的关联与对比,以及 Kotlin 的类型声明的特殊性、val 和 var 的使用、高阶函数的使用、面向表达式编程的使用、字符串的定义与操作等内容;
下水篇—Kotlin 核心(第 3~8 章),深入介绍了面向对象、代数数据类型、模式匹配、类型系统、Lambda、集合、多态、扩展、元编程等 Kotlin 开发核心知识,这是本书的重点,其中涉及很多开发者特别关心的问题,比如多继承问题、模式匹配问题、用代数数据类型抽象业务问题、泛型问题、反射问题等。
潜入篇—Kotlin 探索(第 9~11 章),探索 Kotlin 在设计模式、函数式编程、异步和并发等编程领域的应用,其中包括对 4 大类设计模式、Typeclass 实现、函数式通用结构设计、类型替代异常处理、共享资源控制、CQRS 架构等重点内容的深入剖析;
遨游篇—Kotlin 实战(第 12~13 章),着重演示了 Kotlin 在 Android 和 Web 平台的实战案例,其中涉及架构方式、单向数据流模型、解耦视图导航、响应式编程、Spring 5 响应式框架和编程等内容。

以上关于高阶函数的阐述可能让你对它建立了初步的印象,然而依旧不够清晰。接下来,我们具体看下函数作为参数到底有什么用。需要注意的是,《Java 8 实战》通过一个实现 filter 方法的例子,很好地展现了函数参数化的作用,我们会采用类似的思路,用实际例子来探讨函数作为参数的需求,以及 Kotlin 相关的语法特性。

Shaw 因为旅游喜欢上了地理,然后他建了一个所有国家的数据库。作为一名程序员,他设计了一个 CountryApp 类对国家数据进行操作。Shaw 偏好欧洲的国家,于是他设计了一个程序来获取欧洲的所有国家。

复制代码
data class Country(
val name: String,
val continient: String,
val population: Int)
class CountryApp {
fun filterCountries(countries: List<Country>): List<Country> {
val res = mutableListOf<Country>()
for (c in countries) {
if (c.continient == "EU") { // EU 代表欧洲
res.add(c)
}
}
return res
}
}

以上我们用 data class 声明了一个 Country 数据类,当前也许你会感觉陌生,我们会在下一章详细介绍这种语法。

后来,Shaw 对非洲也产生了兴趣,于是他又改进了上述方法的实现,支持根据具体的洲来筛选国家。

复制代码
fun filterCountries(countries: List<Country>, continient: String): List<Country> {
val res = mutableListOf<Country>()
for (c in countries) {
if (c.continient == continient) {
res.add(c)
}
}
return res
}

以上的程序具备了一定的复用性。然而,Shaw 的地理知识越来越丰富了,他想对国家的特点做进一步的研究,比如筛选具有一定人口规模的国家,于是代码又变成下面这个样子:

复制代码
fun filterCountries(countries: List<Country>, continient: String, population: Int): List<Country> {
val res = mutableListOf<Country>()
for (c in countries) {
if (c.continient == continient && c.population > population) {
res.add(c)
}
}
return res
}

新增了一个 population 的参数来代表人口(单位:万)。Shaw 开始感觉到不对劲,如果按照现有的设计,更多的筛选条件会作为方法参数而不断累加,而且业务逻辑也高度耦合。

解决问题的核心在于对 filterCountries 方法进行解耦,我们能否把所有的筛选逻辑行为都抽象成一个参数呢?传入一个类对象是一种解决方法,我们可以根据不同的筛选需求创建不同的子类,它们都各自实现了一个校验方法。然而,Shaw 了解到 Kotlin 是支持高阶函数的,理论上我们同样可以把筛选的逻辑变成一个方法来传入,这种思路更加简单。

他想要进一步了解这种高级的特性,所以很快就写了一个新的测试类,如代码清单 2-1 所示。

代码清单 2-1
复制代码
class CountryTest {
fun isBigEuropeanCountry(country: Country): Boolean {
return country.continient == "EU" && country.population > 10000
}
}

调用 isBigEuropeanCountry 方法就能够判断一个国家是否是一个人口超过 1 亿的欧洲国家。然而,怎样才能把这个方法变成 filterCountries 方法的一个参数呢?要实现这一点似乎要先解决以下两个问题:

  • 方法作为参数传入,必须像其他参数一样具备具体的类型信息。
  • 需要把 isBigEuropeanCountry 的方法引用当作参数传递给 filterCountries。

接下来,我们先来研究第 1 个问题,即 Kotlin 中的函数类型是怎样的。

Kotlin核心编程(24):基础语法 2.3.2

购书地址 https://item.jd.com/12519581.html?dist=jd

评论

发布