美文网首页
kotlin基础学习-7(扩展,函数式编程,序列相关)

kotlin基础学习-7(扩展,函数式编程,序列相关)

作者: ftd黑马 | 来源:发表于2022-05-04 14:29 被阅读0次
    • 定义扩展函数
      扩展可以在不直接修改类定义的情况下增加类功能,扩展可以用于自定义类,也可以用于比如List,String,以及Kotlin标准库里的其他类。
      和继承相似,扩展也能共享类行为,在无法接触某个类定义或者某个类没有使用open修饰符,导致无法继承的时候,扩展类就是增加类功能的最好选择。
    //在addExt前加上类. ,这里就是扩展了String类的方法,这个方法是,字符串调用该函数返回该字符串+number个!
    fun String.addExt(number:Int) = this + "!".repeat(number)
    
    在main函数中调用
        //因为下面新增了addExt函数,所以字符串都可以调用
        println("abc".addExt(3))
    
    • 超类定义扩展函数
    //超类定义扩展函数
    fun Any.easyPrint() = println()
    
    在main函数中调用
        //超类定义扩展函数
        1.easyPrint()
        "jljklljkl".easyPrint()
    
    • 泛型扩展函数
    //泛型扩展函数,这种写法非常的常见,在标准库函数中,let,also等都是这样写,使用泛型扩展,谁调用这个函数,T就是谁,并且返回当前的T
    fun <T> T.easyPrint2() : T {
        println(this)
        return this
    }
    
    在main函数中调用
        //泛型扩展函数
        "asdf".easyPrint2().addExt(2).easyPrint2()
    
    • 扩展属性
      除了给类添加功能扩展函数外,还可以给类定义扩展属性
    //给String类添加一个扩展属性,这个属性可以统计字符串里有多少个元音字母
    val String.numVowel
        get() = count{"aeiou".contains(it)}
    
    在main函数中调用
        "abcdefghijklmn".numVowel.easyPrint2()
    
    • 可空类型扩展函数
    //可空类型扩展函数,在扩展函数内解决可能出现的空值问题
    fun String?.nullableWithDefault(default: String) = println(this?:default)
    
    在main函数中调用
        val nullable:String?= null
        nullable.nullableWithDefault("abc")
    
    • infix关键字
      infix关键字适用于有单个参数的扩展类函数,可以更"简洁"的调用。
      如果一个函数定义了infix关键字,那么调用它时,调用者和函数之间的.以及参数的一对括号都可以不要。
    infix fun String?.nullableWithDefault2(default: String) = println(this?:default)
    
    在main函数中调用
        //可空类型扩展函数
        val nullable:String?= null
        nullable.nullableWithDefault("abc")
        //如果函数加了infix,那么上面这个可空类型扩展函数就可以这么写了
        //    mapOf("jack" to 18),map集合的写法点击to看源码,就是用infix关键字修饰
        nullable nullableWithDefault2 "abc"
    
    • 定义扩展文件
      定义扩展文件,扩展函数需要在多个文件里面使用,可以将它定义在单独的文件,然后import。
      新生成扩展文件Extention.kt,如下:
    package com.ftd.extention
    
    //定义扩展文件,扩展函数需要在多个文件里面使用,可以将它定义在单独的文件,然后import
    fun <T> Iterable<T>.randomTake() = this.shuffled().first()
    

    在别的文件中调用:

    package com.example.myapplication
    
    import com.ftd.extention.randomTake as randomTake2  //这里可以重命名
    
    fun main() {
        //定义扩展文件,扩展函数需要在多个文件里面使用,可以将它定义在单独的文件,然后import
        val list = listOf("jack","tom","jason")
        val set = setOf("java","android","python")
    
    //    list.shuffled().first()
        //使用扩展文件里面的扩展函数
    //    list.randomTake()
    
        //重命名扩展
        list.randomTake2()
    }
    
    • 函数式编程
      主要依赖于高阶函数(以函数为参数或者或返回函数)返回的数据,专用于处理各种数据集合,最经典的莫过于rxjava
      函数类别
      一个函数式应用通常由三大类函数构成:变换transfrom,过滤filter,合并combine。每类函数都针对集合数据类型设计,目标式产生一个最终结果。
      函数式编程用到的函数生来都是可以组合的,也就是说,可以组合多个简单函数来构建复杂的计算行为。
      1.变换函数
      变换是函数式编程的第一大类函数,变换函数会遍历集合内容,用一个以值参形式传入的变换器函数,变换每一个元素,然后返回包含已修改元素的集合给链上的其他函数。
      最常用的两个变换函数式map和flatMap
        //map变换函数会遍历接收者集合,让变换器函数作用于集合里的各个元素,返回结果是包含已修改元素的集合,会作为链上下一个函数的输入。
        val animals = listOf("tiger","cat","dog")
        val babies = animals.map {
            animal -> "A baby $animal"
        }
    
        //打印可以看到,原始集合并没有被修改,map变换函数和自己定义的变化器函数做完事情后返回的是一个新集合
        println(animals)
        println(babies)
    
        //map返回的集合中的元素个数和输入集合必须一样,不过,返回的新集合的里的元素可以是不同类型的
        val animalLength = animals.map { it.length }
        println(animalLength)
    
        //flatmap函数操作一个集合的集合,将其中多个集合的元素合并后返回一个包含所有元素的单一集合
        val list = listOf(listOf(1,2,3), listOf(4,5,6)).flatMap { it }
        println(list)//这里的打印结果是[1,2,3,4,5,6]
    

    2.过滤函数filter
    过滤是函数式编程的第二大类函数,过滤函数接收一个predicate函数,用它按给定条件检查接收者集合里的元素并给出true或者false的判定。
    如果返回true,受检元素就会添加到过滤函数返回的新的集合里,如果是false,就会从新集合里移除。

        //过滤集合里含有"J"的元素
        val names = listOf("Jack","Rose","Jimmy","Tom")
        val jNames= names.filter { it.contains("J") }
        println(jNames)  // 这里打印的是[Jack, Jimmy]
        
        //Demo,组合使用map和filter找质数(只能被1和自身整除)
        val numbers = listOf(4,22,7,39,53,11,55)
        val numbersZhi = numbers.filter {
            //这里的number就是集合里的每一个值,这里的第一个it指的是(2到nunber中的每一个值),第二个it指的是所有number取模后的值
                number ->
            (2 until number).map { number % it }.none { it == 0 }
        }
        println(numbersZhi)
    

    3.合并函数
    合并是函数式编程的第三大类函数,合并函数能将不同不同的集合合并成一个新集合,但是和flatmap不一样。
    例如zip和fold

        //zip合并函数来合并两个集合,返回一个包含键值对的新集合
        val employee = listOf("jack","tom","rose")
        val sizes = listOf(15,20,40)
        val toMap = employee.zip(sizes).toMap()
        println(toMap["rose"])
    
        //fold函数用来合并值,这个合并函数接收一个初始的值,随后会根据匿名函数的结果更新
        val fold = listOf(1, 2, 3, 4).fold(0) { total, number ->
            total + number * 3
        }
        println(fold) // 这里的值 = 0+1*3 + 2*3 + 3*3 + 4*3
    
    • 序列
    package com.example.myapplication
    
    /**
     *
     * list,set,map集合类型,这几个集合类型统称为及早集合,这些集合的任何一个实例在创建后,它要包含的元素都会被加入并且允许访问。
     * 对应及早集合,kotlin还有另外一类集合:惰性集合。类似于类的惰性初始化,惰性集合类型的性能表现优异,尤其是用于包含大量元素的集合时,因为集合元素是按需产生的
     *
     *
     *
     *
     * 序列
     * kotlin有个内置惰性集合类型叫序列(Sequence),序列不会索引排序它的内容,也不记录元素数目。
     * 在使用一个序列时,序列里的值可能由无限多,因为某个数据源能产生无限多个元素。
     *
     *
     */
    
    
    fun Int.isPrime():Boolean{
        (2 until this).map {
            if (this % it == 0){
                return false
            }
        }
        return true
    }
    
    
    fun main() {
    
        //demo,假设想产生头1000个质数。
    
        //针对这个需求,我们并不知道1000个质数到哪里,所以假设0-5000里就包含1000个质数。
        val take = (2..5000).toList().filter { it.isPrime() }.take(1000)
        println(take.size) // 但是此时打印结果是669,不够1000个,所以这种写法还需要加while判断
    
        //使用序列,这里的链式调用执行顺序应该不是顺序执行的,因为这个generateSequence方法和take方法都是Sequence重写过的,内部肯定是有关联。
        val sequenceTake = generateSequence(2) { value ->
            value + 1
        }.filter { it.isPrime() }.take(1000)
        println(sequenceTake.toList().size)//此时执行结果就是1000
    }
    

    相关文章

      网友评论

          本文标题:kotlin基础学习-7(扩展,函数式编程,序列相关)

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