Kotlin 进阶之路 目录
高阶函数的基本概念
传入或者返回函数的函数
函数引用 ::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)
我是中国人
来源: http://www.jianshu.com/p/e061ddbb973d