高阶函数的基本概念
- 传入或者返回函数的函数
- 函数引用 ::println
- 带有Receiver的引用 pdfPrinter::println
fun main(args: Array<String>) {
val country = arrayOf("Britain", "France", "China", "Japan", "American", "Germany")
//1.直接引用
country.forEach(::println)
println("--------------------------------")
//2.类名引用 Hello类名 String::isNotEmpty String 类名
val helloWorld = Hello::world
country.filter(String::isNotEmpty).forEach(::println)
println("--------------------------------")
//3.调用者引用方法
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
常见高阶函数
- 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)
//常规写法 啰嗦
// val newList = ArrayList<Int>()
// list.forEach {
// val newElement = it * 2 + 3
// newList.add(newElement)
// }
println("----------------map----------------")
//高阶函数
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 给一个初始值,各阶乘求和----------------")
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 过滤 值符合条件的数----------------")
println((0..6).map(::factorial).filter { it % 2 == 1 })
println("----------------filterIndexed 过滤数所在位置符合条件的数----------------")
println((0..6).map(::factorial).filterIndexed { index, i -> index % 2 == 1 })
println("----------------takeWhile 取符合条件的数直到----------------")
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 给一个初始值,各阶乘求和----------------
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 过滤 值符合条件的数----------------
[1, 1]
----------------filterIndexed 过滤数所在位置符合条件的数----------------
[1, 6, 120]
----------------takeWhile 取符合条件的数直到----------------
[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----------------
你好!
尾递归优化
- 递归的一种特殊形式
- 调用自身后无其他操作
- tailrec关键字提示编译器尾递归优化
- 尾递归与迭代的关系
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
注:当MAX_NODE_COUNT数很大 而去掉 tailrec关键字,会报错
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)
闭包
- 函数运行的环境
- 持有函数运行状态
- 函数内部可以定义函数
- 函数内部也可以定义类
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
函数复合
- f(g(x))
- 如何实现函数符合
- 回顾: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 是参数
* P2 是参数
* R 是回调参数
* */
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的概念
- 简单说就是多元函数变换成一元函数调用链
- 了解Currying的实现方法
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.
偏函数
- 理解偏函数的概念
- 传入部分参数得到新的函数
- 仔细体会与Currying的不同
- 了解偏函数的实现方法
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 = "我是中国人".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)
我是中国人
网友评论