高階函數(shù)的基本概念
- 傳入或者返回函數(shù)的函數(shù)
- 函數(shù)引用 ::println
- 帶有Receiver的引用 pdfPrinter::println
fun main(args: Array<String>) {
val country = arrayOf("Britain", "France", "China", "Japan", "American", "Germany")
//1.直接引用
country.forEach(::println)
println("--------------------------------")
//2.類(lèi)名引用 Hello類(lèi)名 String::isNotEmpty String 類(lèi)名
val helloWorld = Hello::world
country.filter(String::isNotEmpty).forEach(::println)
println("--------------------------------")
//3.調(diào)用者引用方法
val pdfPrinter = PdfPrinter()
country.forEach(pdfPrinter::println)
}
class PdfPrinter {
fun println(any: Any) {
kotlin.io.println(any)
}
}
class Hello {
fun world() {
println("Hello World.")
}
}
Britain
France
China
Japan
American
Germany
--------------------------------
Britain
France
China
Japan
American
Germany
--------------------------------
Britain
France
China
Japan
American
Germany
常見(jiàn)高階函數(shù)
- map/flatMap
- fold/reduce
- filter/takeWhile
- let/apply/with/use
fun main(args: Array<String>) {
val list = listOf(1, 3, 4, 5, 10, 8, 2)
//常規(guī)寫(xiě)法 啰嗦
// val newList = ArrayList<Int>()
// list.forEach {
// val newElement = it * 2 + 3
// newList.add(newElement)
// }
println("----------------map----------------")
//高階函數(shù)
val newList = list.map { it * 2 + 3 }
newList.forEach(::println)
val newList2 = list.map(Int::toDouble)
newList2.forEach(::println)
println("----------------flatMap----------------")
val list3 = listOf(1..4, 2..6, 100..102)
list3.forEach(::println)
val flatList = list3.flatMap { it }
flatList.forEach(::println)
val flatList2 = list3.flatMap { intRange ->
intRange.map { intElement -> "No.$intElement" }
}
flatList2.forEach(::println)
println("----------------求和----------------")
println(flatList.reduce { acc, i -> acc + i })
println("----------------求階乘----------------")
(0..6).map(::factorial).forEach(::println)
println("----------------fold 給一個(gè)初始值,各階乘求和----------------")
println((0..6).map(::factorial).fold(5) { acc, i ->
acc + i
})
println("----------------fold 拼接----------------")
println((0..6).map(::factorial).fold(StringBuilder()) { acc, i ->
acc.append(i).append(",")
})
println("----------------joinToString 拼接----------------")
println((0..6).joinToString(","))
println("----------------foldRight倒著拼接----------------")
println((0..6).map(::factorial).foldRight(StringBuilder()) { i, acc ->
acc.append(i).append(",")
})
println("----------------filter 過(guò)濾 值符合條件的數(shù)----------------")
println((0..6).map(::factorial).filter { it % 2 == 1 })
println("----------------filterIndexed 過(guò)濾數(shù)所在位置符合條件的數(shù)----------------")
println((0..6).map(::factorial).filterIndexed { index, i -> index % 2 == 1 })
println("----------------takeWhile 取符合條件的數(shù)直到----------------")
println((0..6).map(::factorial).takeWhile { it % 2 == 1 })
}
fun factorial(n: Int): Int {
if (n == 0) return 1
return (1..n).reduce { acc, i -> acc * i }
}
----------------map----------------
5
9
11
13
23
19
7
1.0
3.0
4.0
5.0
10.0
8.0
2.0
----------------flatMap----------------
1..4
2..6
100..102
1
2
3
4
2
3
4
5
6
100
101
102
No.1
No.2
No.3
No.4
No.2
No.3
No.4
No.5
No.6
No.100
No.101
No.102
----------------求和----------------
333
----------------求階乘----------------
1
1
2
6
24
120
720
----------------fold 給一個(gè)初始值,各階乘求和----------------
879
----------------fold 拼接----------------
1,1,2,6,24,120,720,
----------------joinToString 拼接----------------
0,1,2,3,4,5,6
----------------foldRight倒著拼接----------------
720,120,24,6,2,1,1,
----------------filter 過(guò)濾 值符合條件的數(shù)----------------
[1, 1]
----------------filterIndexed 過(guò)濾數(shù)所在位置符合條件的數(shù)----------------
[1, 6, 120]
----------------takeWhile 取符合條件的數(shù)直到----------------
[1, 1]
import java.io.BufferedReader
import java.io.FileReader
data class Person(val name: String, val age: Int) {
fun work() {
println("$name is working!!!")
}
}
fun main(args: Array<String>) {
println("----------------let----------------")
findPerson()?.let { person ->
println(person.name)
println(person.age)
}
findPerson()?.let { (name, age) ->
println(name)
println(age)
}
findPerson()?.let { person ->
person.work()
println(person.age)
}
println("----------------apply----------------")
findPerson()?.apply {
work()
println(age)
}
println("----------------with----------------")
val br = BufferedReader(FileReader("E:\\hello.txt"))
with(br) {
var line: String?
while (true) {
line = readLine() ?: break
println(line)
}
close()
}
println("----------------use----------------")
BufferedReader(FileReader("E:\\hello.txt")).use {
var line: String?
while (true) {
line = it.readLine() ?: break
println(line)
}
}
println("----------------readText----------------")
val brNew = BufferedReader(FileReader("E:\\hello.txt")).readText()
println(brNew)
}
fun findPerson(): Person? {
return Person("John", 28)
}
----------------let----------------
John
28
John
28
John is working!!!
28
----------------apply----------------
John is working!!!
28
----------------with----------------
你好!
----------------use----------------
你好!
----------------readText----------------
你好!
尾遞歸優(yōu)化
- 遞歸的一種特殊形式
- 調(diào)用自身后無(wú)其他操作
- tailrec關(guān)鍵字提示編譯器尾遞歸優(yōu)化
- 尾遞歸與迭代的關(guān)系
data class ListNode(val value: Int, var next: ListNode? = null)
tailrec fun findListNode(head: ListNode?, value: Int): ListNode? {
head ?: return null
if (head.value == value) return head
return findListNode(head.next, value)
}
data class TreeNode(val value: Int) {
var left: TreeNode? = null
var right: TreeNode? = null
}
fun findTreeNode(root: TreeNode?, value: Int): TreeNode? {
root ?: return null
if (root.value == value) return root
return findTreeNode(root.left, value) ?: return findTreeNode(root.right, value)
}
fun main(args: Array<String>) {
val MAX_NODE_COUNT = 100000
val head = ListNode(0)
var p = head
for (i in 1..MAX_NODE_COUNT) {
p.next = ListNode(i)
p = p.next!!
}
println(findListNode(head, MAX_NODE_COUNT - 2)?.value)
}
99998
注:當(dāng)MAX_NODE_COUNT數(shù)很大 而去掉 tailrec關(guān)鍵字,會(huì)報(bào)錯(cuò)
Exception in thread "main" java.lang.StackOverflowError
at chapter5.tailrecursive.MainKt.findListNode(Main.kt:8)
at chapter5.tailrecursive.MainKt.findListNode(Main.kt:8)
at chapter5.tailrecursive.MainKt.findListNode(Main.kt:8)
at chapter5.tailrecursive.MainKt.findListNode(Main.kt:8)
at chapter5.tailrecursive.MainKt.findListNode(Main.kt:8)
at chapter5.tailrecursive.MainKt.findListNode(Main.kt:8)
at chapter5.tailrecursive.MainKt.findListNode(Main.kt:8)
at chapter5.tailrecursive.MainKt.findListNode(Main.kt:8)
閉包
- 函數(shù)運(yùn)行的環(huán)境
- 持有函數(shù)運(yùn)行狀態(tài)
- 函數(shù)內(nèi)部可以定義函數(shù)
- 函數(shù)內(nèi)部也可以定義類(lèi)
fun fibonacci(): Iterable<Long> {
var first = 0L
var second = 1L
return Iterable {
object : LongIterator() {
override fun nextLong(): Long {
val result = second
second += first
first = second - first
return result
}
override fun hasNext() = true
}
}
}
fun main(args: Array<String>) {
for (i in fibonacci()) {
if (i > 100) break
println(i)
}
println("--------------------------------")
val add5 = add(5)
println(add5(2))
}
fun add(x: Int): (Int) -> Int {
data class Person(val name: String, val age: Int)
return fun(y: Int): Int {
return x + y
}
}
1
2
3
5
8
13
21
34
55
89
--------------------------------
7
函數(shù)復(fù)合
- f(g(x))
- 如何實(shí)現(xiàn)函數(shù)符合
- 回顧:infix的使用
val add5 = { i: Int -> i + 5 } //f(x)
val multiplyBy2 = { i: Int -> i * 2 }//g(x)
fun main(args: Array<String>) {
println(multiplyBy2(add5(8))) //(5 + 8)* 2
val add5AndMultiplyBy2 = add5 andThen multiplyBy2
val add5ComposeMultiplyBy2 = add5 compose multiplyBy2
println(add5AndMultiplyBy2(8)) //m(x) =f(g(x))
println(add5ComposeMultiplyBy2(8)) //m(x)=g(f(x))
}
/**
* P1 是參數(shù)
* P2 是參數(shù)
* R 是回調(diào)參數(shù)
* */
infix fun <P1, P2, R> Function1<P1, P2>.andThen(function: Function1<P2, R>): Function1<P1, R> {
return fun(p1: P1): R {
return function.invoke(this.invoke(p1))
}
}
infix fun <P1, P2, R> Function1<P2, R>.compose(function: Function1<P1, P2>): Function1<P1, R> {
return fun(p1: P1): R {
return this.invoke(function.invoke(p1))
}
}
26
26
21
Currying
- 理解Currying的概念
- 簡(jiǎn)單說(shuō)就是多元函數(shù)變換成一元函數(shù)調(diào)用鏈
- 了解Currying的實(shí)現(xiàn)方法
import java.io.OutputStream
fun log(tag: String, target: OutputStream, message: Any?) {
target.write("[$tag] $message\n".toByteArray())
}
//原方案
//fun log(tag:String)
// = fun(target:OutputStream)
// = fun(message:Any?)
// = target.write("[$tag] $message\n".toByteArray())
//curried方案
fun <P1, P2, P3, R> Function3<P1, P2, P3, R>.curried() = fun(p1: P1) = fun(p2: P2) = fun(p3: P3) = this(p1, p2, p3)
fun main(args: Array<String>) {
log("kpioneer", System.out, "HelloWorld")
// log("kpioneer")(System.out)("HelloWorld Again.")
::log.curried()("kpioneer")(System.out)("HelloWorld Again.")
}
[kpioneer] HelloWorld
[kpioneer] HelloWorld Again.
偏函數(shù)
- 理解偏函數(shù)的概念
- 傳入部分參數(shù)得到新的函數(shù)
- 仔細(xì)體會(huì)與Currying的不同
- 了解偏函數(shù)的實(shí)現(xiàn)方法
import java.io.OutputStream
import java.nio.charset.Charset
fun log(tag: String, target: OutputStream, message: Any?) {
target.write("[$tag] $message\n".toByteArray())
}
//原方案
//fun log(tag:String)
// = fun(target:OutputStream)
// = fun(message:Any?)
// = target.write("[$tag] $message\n".toByteArray())
//curried方案
fun <P1, P2, P3, R> Function3<P1, P2, P3, R>.curried() = fun(p1: P1) = fun(p2: P2) = fun(p3: P3) = this(p1, p2, p3)
fun main(args: Array<String>) {
// log("kpioneer", System.out, "HelloWorld")
// // log("kpioneer")(System.out)("HelloWorld Again.")
// ::log.curried()("kpioneer")(System.out)("HelloWorld Again.")
//
// val consoleLogWithTag = (::log.curried())("kpioneer")(System.out)
// consoleLogWithTag("HelloWorld Again.")
val bytes = "我是中國(guó)人".toByteArray(charset("GBK"))
val stringFromGBK = makeStringFromGbkByte(bytes)
println(stringFromGBK)
}
val makeString = fun(byteArray: ByteArray, charset: Charset): String {
return String(byteArray, charset)
}
val makeStringFromGbkByte = makeString.partial2(charset("GBK"))
fun <P1, P2, R> Function2<P1, P2, R>.partial2(p2: P2) = fun(p1: P1) = this(p1, p2)
我是中國(guó)人