《Kotlin核心编程》 ——2.3.2 实例:函数作为参数的需求
2.3.2 实例:函数作为参数的需求
以上关于高阶函数的阐述可能让你对它建立了初步的印象,然而依旧不够清晰。接下来,我们具体看下函数作为参数到底有什么用。需要注意的是,《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
调用isBigEuropeanCountry方法就能够判断一个国家是否是一个人口超过1亿的欧洲国家。然而,怎样才能把这个方法变成filterCountries方法的一个参数呢?要实现这一点似乎要先解决以下两个问题:
方法作为参数传入,必须像其他参数一样具备具体的类型信息。
需要把isBigEuropeanCountry的方法引用当作参数传递给filterCountries。
接下来,我们先来研究第1个问题,即Kotlin中的函数类型是怎样的。
- 点赞
- 收藏
- 关注作者
评论(0)