1.定义
如果一个函数接收另一个函数作为参数,或者返回值的类型是另一个函数,那么该函数就称为高阶函数。
系统中已经有很多,示例:库函数 在 Standard.kt 标准库中提供了一些便捷的内置高阶函数
例如let with run apply also等
例如:
a.let {
}
2.看一下简单的使用
fun min(num1: Int, num2: Int): Int {
return num1 - num2
}
fun plus(num1: Int, num2: Int): Int {
return num1 + num2
}
// 有的同学可能奇怪以下block参数的写法,是由lambda表达式简化而来,可以重新补充以下lambda表达式的相关知识,接下来会有一些捎带的讲解
fun func1(num1: Int, num2: Int, block: (Int, Int) -> Int): Int {
return block(num1, num2)
}
fun func2(type: String): (Int, Int) -> Int {
if (type == "min") {
return ::min
} else {
return ::plus
}
}
fun main(args: Array<String>) {
//使用如下
val result1min = func1(1, 2, ::min)
val result1plus = func1(1, 2, ::plus)
println("result1-:$result1min")
println("result1+:$result1plus")
val result = func2("min")
//返回是一个函数,可以调用
val result2 = result(1, 2)
println("result2:$result2")
因为每次都要声明一个方法,很麻烦,可以做以下优化
// val result3 = func1(1, 2, fun(n1: Int, n2: Int): Int {
// return n1 + n2
// })
// println("result3:result3")
简化
// val func2 = func(1, 2, { n1, n2 -> n1 + n2 })
// val func3 = func1(1, 2) { n1, n2 -> n1 + n2 }
}
3.简单的实际应用
// 当我们求这个列表中最长字符串长度时,可以写出如下代码
val list = listOf("Apple", "Banana", "Orange", "Pear", "Grape", "Watermelon")
val maxLengthFruit1 = list.maxBy {
it.length
}
maxBy是kotlin自带的高阶函数方法
让我们一起实现一下maxBy相同功能
fun main(args: Array<String>) {
//这样可以达到一个方法可以多处使用
//比如一个商品列表,可以检索最长的商品名称,或者最长的生产厂家
//只需要传入不同的参数函数
val maxLengthStr = list.maxLength {
it.length
}
//如何简化的
//因为是传递了一个函数作为参数
val maxLengthFruit0 = list.maxLength(fun(str: String): Int {
return str.length
})
//首先,我们可以直接将lambda表达式传入maxBy函数当中,因此第一步简化如下所示:
val maxLengthFruit1 = list.maxLength({ fruit: String -> fruit.length })
//当Lambda 参数是函数的最后一个参数时,可以将Lambda 表达式移到函数括号的外面
val maxLengthFruit2 = list.maxLength(){ fruit: String -> fruit.length }
//如果Lambda 参数是函数的唯一一个参数的话,还可以将函数的括号省略
val maxLengthFruit3 = list.maxLength{ fruit: String -> fruit.length }
//由于Kotlin拥有出色的类型推导机制,Lambda 表达式中的参数列表其实在大多数情况下不必声明参数类型
val maxLengthFruit4 = list.maxLength{ fruit -> fruit.length }
//当Lambda 表达式的参数列表中只有一个参数时,也不必声明参数名,而是可以使用it关键字来代替
val maxLengthFruit5 = list.maxLength{
it.length
}
println(maxLengthStr)
// 由以下简化而来
}
//自定义扩展函数
fun List<String>.maxLength(block: (String) -> Int): String {
var str = ""
// val iterator = iterator()
/**
* 扩展小知识
*
* 如果没有使用Iterator,遍历一个数组的方法是使用索引:
* for(int i=0; i<array.size(); i++) { ... get(i) ... }
* 而访问一个链表(LinkedList)又必须使用while循环:
* while((e=e.next())!=null) { ... e.data() ... }
* 如果以后需要把ArrayList更换为LinkedList,则原来的客户端代码必须全部重写。
* 为解决以上问题,Iterator模式总是用同一种逻辑来遍历集合:
* for(Iterator it = c.iterater(); it.hasNext(); ) { ... }
* 奥秘在于客户端自身不维护遍历集合的"指针",所有的内部状态(如当前元素位置,是否有下一个元素)
* 都由Iterator来维护,
* 而这个Iterator由集合类通过工厂方法生成,因此,它知道如何遍历整个集合。
* 客户端从不直接和集合类打交道,它总是控制Iterator,
* 向它发送"向前","向后","取当前元素"的命令,就可以间接遍历整个集合。
*/
for (fruit in this) {
if (block(fruit) > str.length) {
str = fruit
}
}
return str
}
3.1 也可以用作简单的接口回调(多个参数一个函数)
fun show(isShow: Boolean, callback: (String) -> Unit) {
if (isShow) {
callback("高阶 show")
}
}
fun use(){
//写法一
show(true, callback = {it->
println("高阶函数返回结果:$it")
})
//写法二
show(true, {it->
println("高阶函数返回结果:$it")
})
//写法三
show(true) {
println("高阶函数返回结果:$it")
}
}
fun main() {
use()
}