Kotlin 函數(shù)6 - 高階函數(shù)

Kotlin 函數(shù)6 - 高階函數(shù)


1. 基本概念

簡(jiǎn)單的說(shuō),高階函數(shù)就是把一個(gè)函數(shù)作為另一個(gè)函數(shù)的參數(shù)或者返回值的函數(shù),

  1. 舉個(gè)例子:
Array.forEach(action: (T) -> Unit): Unit

上面的 forEach() 函數(shù)參數(shù)是一個(gè) 接收一個(gè)任意類(lèi)型參數(shù),同時(shí)沒(méi)有返回值 的函數(shù),所以只要符合要求的函數(shù)都可以作為其參數(shù)使用;

val array = arrayOf("a", "b", "", "c", "d", "e", "f")
array.forEach({ element -> println(element) })

根據(jù)之前使用 lambda 表達(dá)式的經(jīng)驗(yàn),我們可以將其簡(jiǎn)化成

array.forEach { println(it) }
  1. 使用 雙冒號(hào)(::) 操作符來(lái)獲取函數(shù)的引用

:: 操作符常用于

  1. 獲取KClass引用
  2. 獲取函數(shù)引用
  3. 獲取屬性引用
  4. 獲取構(gòu)造函數(shù)引用獲取KClass引用
  • 所以上面的語(yǔ)句還可以寫(xiě)作
array.forEach(::println)

這里的函數(shù)引用引用的是包級(jí)函數(shù),此外還有另外兩種:

  • 使用類(lèi)名調(diào)用(這種方式有一個(gè)隱含參數(shù),就是調(diào)用者自己)
println(array.size) // 7
val newArray = array.filter(String::isNotEmpty)
print(newArray.size) // 6
  • 再一個(gè)就是利用實(shí)例來(lái)調(diào)用
class MyPrint {
    fun out(any: Any) {
        println(any)
    }
}

val myPrint = MyPrint()
array.forEach(myPrint::out)

2. 常見(jiàn)的高階函數(shù)

forEach / map / flatMap

  1. 假設(shè)有一個(gè)整形的 List,需要將 List 中的每一個(gè)元素?cái)U(kuò)大3被得到一個(gè)新的 List
val list = listOf(1, 2, 3, 4, 5, 6)
val newList = ArrayList<Int>()
list.forEach{
    var item = it*3
    newList.add(item)
}
  1. 這里,我們可以用 map 來(lái)簡(jiǎn)化處理
val list = listOf(1, 2, 3, 4, 5, 6)
val newList = list.map { it * 3 }
  1. flatMap
val list = listOf(7..14, 2..5, 10..17)

val flatList = list.flatMap { it }
val flatList = list.flatMap {
    it.map { "No. $it" }
}
val flatList = list.flatMap { itRange ->
    itRange.map { itItem ->
        "No. $itItem"
    }
}
  1. reduce
  • 利用 reduce 求 1..100 的和
println((1..100).reduce { acc, s -> acc + s }) //5050
  • 利用 reduce 求 10 的階乘
println((1..10).reduce { acc, s -> acc * s }) //3628800
  • 利用 reduce 求 0..10 的階乘
fun factorial(n: Int): Int {
    if (0 == n) {
        return 1
    }
    return (1..n).reduce { acc, i -> acc * i }
}

(0..10).map(::factorial).forEach(::println)

結(jié)果

1
1
2
6
24
120
720
5040
40320
362880
3628800
  1. fold 帶有初始值的 reduce
println((0..10).map(::factorial).reduce { acc, i -> acc+i }) // 4037914
println((0..10).map(::factorial).fold(1) { acc, i -> acc+i }) // 4037915
  • 利用 fold 拼接字符串
println((0..10).map(::factorial).fold(StringBuilder()) { acc, i -> acc.append(i).append(",") })
// 1,1,2,6,24,120,720,5040,40320,362880,3628800,
println((0..10).map(::factorial).foldIndexed(StringBuilder()) { index,acc, i -> acc.append(index).append("->").append(i).append(",") })
0->1,1->1,2->2,3->6,4->24,5->120,6->720,7->5040,8->40320,9->362880,10->3628800,
  • 利用 foldRight 倒序拼接字符串
println((0..10).map(::factorial).foldRight(StringBuilder()) { i,acc -> acc.append(i).append(",") })
// 3628800,362880,40320,5040,720,120,24,6,2,1,1,
println((0..10).map(::factorial).foldRightIndexed(StringBuilder()) {index, i,acc -> acc.append(index).append("->").append(i).append(",") })
10->3628800,9->362880,8->40320,7->5040,6->720,5->120,4->24,3->6,2->2,1->1,0->1,
  1. filter

保留 0..10 階乘結(jié)果為奇數(shù)的結(jié)果

println((0..10).map(::factorial).filter { it % 2 == 1 }) // [1, 1]

保留 0..10 階乘結(jié)果索引是奇數(shù)位的結(jié)果

println((0..10).map(::factorial).filterIndexed { index, i -> index % 2 == 1 }) // [1, 6, 120, 5040, 362880]
  1. takeWhile

取出數(shù)組中奇數(shù)值,一旦遇到偶數(shù),停止取值

val listB = listOf(1, 3, 5, 6, 7, 8, 9, 10, 13)
println(listB.takeWhile { it % 2 == 1 }) // [1, 3, 5]

在上述要求上,倒序取值

println(listB.takeLastWhile { it % 2 == 1 }) // [13]
  1. let apply
data class Person(var name: String, var age: Int) {
    fun work() {
        println("$name is working!")
    }
}

fun findPerson(age: Int): Person? {
    if (age <= 0) {
        return null
    }
    return Person("Tom", 18)
}
findPerson(-1)?.let { person ->
    person.work()
    println(person.age)
}
findPerson(-1)?.apply {
    work()
    println(age)
}
  1. whit use

模擬讀取文件

val br = BufferedReader(FileReader("hello.txt"))
with(br) {
    var line: String?
    while (true) {
        line = readLine() ?: break
        println(line)
    }
    close()
}
BufferedReader(FileReader("hello.txt")).use {
    var line: String?
    while (true) {
        line = it.readLine() ?: break
        println(line)
    }
}
  1. 這里需要使用 it 做指代;
  2. 使用 use,可省略 close() 函數(shù);
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 函數(shù)和對(duì)象 1、函數(shù) 1.1 函數(shù)概述 函數(shù)對(duì)于任何一門(mén)語(yǔ)言來(lái)說(shuō)都是核心的概念。通過(guò)函數(shù)可以封裝任意多條語(yǔ)句,而且...
    道無(wú)虛閱讀 4,957評(píng)論 0 5
  • 前言 人生苦多,快來(lái) Kotlin ,快速學(xué)習(xí)Kotlin! 什么是Kotlin? Kotlin 是種靜態(tài)類(lèi)型編程...
    任半生囂狂閱讀 26,703評(píng)論 9 118
  • 你不是什么時(shí)候,隨著我的靈魂,來(lái)到世間。 我只知道,我持劍,打馬而過(guò),不留下一點(diǎn)煙塵。 我不是屬于瞬間的星星,曇花...
    歲月溫涼閱讀 389評(píng)論 0 1
  • 我立在窗前 春風(fēng)拂面 猶如情人的吻 意醉心甜 我漫步公園 春風(fēng)拂面 猶如母親的手 溫馨柔軟 我攀上山巔 春風(fēng)拂面 ...
    艾思閱讀 750評(píng)論 35 47

友情鏈接更多精彩內(nèi)容