Kotlin 进阶之路9 高阶函数

作者: 香沙小熊 | 来源:发表于2018-06-02 18:37 被阅读96次

    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)
    
    我是中国人
    

    相关文章

      网友评论

        本文标题:Kotlin 进阶之路9 高阶函数

        本文链接:https://www.haomeiwen.com/subject/gkwfsftx.html