美文网首页
kotlin--扩展

kotlin--扩展

作者: aruba | 来源:发表于2021-08-25 15:33 被阅读0次

    之间使用了kotlin的标准函数、匿名函数,觉得它十分灵活,简便。其实kotlin的标准函数就是用了扩展

    一、扩展函数

    1.定义扩展函数

    当我们需要对一个类新增一个方法时,在Java中需要写一个子类继承它,然后添加我们的新方法。
    在kotlin中,可以利用扩展增加类的功能,指定类名后就可以新增函数
    我们给所有类新增打印函数,给String新增加上!的方法:

    //给所有类新增打印函数 :Any.函数名()
    fun Any.print() = println(this)
    
    //给String新增加上!的方法
    fun String.addExt(count: Int) = this + "!".repeat(count)
    
    fun main() {
        "abc".print().print()
    }
    
    2.泛型扩展函数

    如果想要链式调用我们刚刚新增的函数,先调用下打印,再调用新增!,最后再调用打印是不行的

    fun main() {
        "abc".print().addExt(5).print()
    }
    

    由于print的返回是Any类,但是addExt函数只有String类才有,所以我们需要将print的返回改为String类,但是我又想保持所有类都有print函数,那怎么办呢?
    答案是将print函数返回泛型类型,哪个类调用的就返回哪个类

    //定义泛型类型扩展函数
    fun <T> T.print(): T {
        println(this)
        return this
    }
    
    //给String新增加上!的方法
    fun String.addExt(count: Int) = this + "!".repeat(count)
    
    fun main() {
        "abc".print().addExt(5).print()
    }
    

    结果:
    abc
    abc!!!!!

    泛型扩展函数在标准函数中随处可见,比如let

    public inline fun <T, R> T.let(block: (T) -> R): R {
        contract {
            callsInPlace(block, InvocationKind.EXACTLY_ONCE)
        }
        return block(this)
    }
    

    二、扩展属性

    1.除了给类扩展函数外,也可以扩展属性

    String新增属性,计数元音个数:

    //String新增属性,计数元音个数
    val String.count
        get() = this.count{ "auieoy".contains(it) }
    
    fun main() {
        "The people's Republic of China".count.print()
    }
    
    2.扩展函数也可以定义于可空类型

    可以直接在扩展函数内部处理空的情况

    fun String?.printDefault(default: String) = print(this ?: default)
    
    fun main() {
        val s: String? = null
        s.printDefault("123")
    }
    
    3.infix

    infix适用于单个入参的扩展函数,可以使语法更简洁,调用方法时的.和()都可以去除

    infix fun String?.printDefault(default: String) = print(this ?: default)
    
    fun main() {
        val s: String? = null
        s printDefault "123"
    }
    
    4.扩展文件

    为了统一管理,如果想要在多个文件使用扩展函数,可以将它定义在一个单独文件里
    定义一个随机函数:

    package com.aruba.mykotlinapplication.extension
    
    /**
    
     * Created by aruba on 2021/8/25.
    
     */
    inline fun <T> Iterable<T>.randomTake() = shuffled().first()
    

    别的文件使用import导入:

    import com.aruba.mykotlinapplication.extension.randomTake
    
    fun main() {
        println(listOf(4, 7, 9).randomTake())
    }
    
    5.重命名扩展

    可以使用as关键字重命名它的名字

    import com.aruba.mykotlinapplication.extension.randomTake as random
    
    fun main() {
        println(listOf(4, 7, 9).random())
    }
    

    三、DSL

    apply函数中,匿名函数中我们可以直接调用接收者的方法,像这种编程范式,业界称为”领域特定语言“,以暴露接收者的函数和特性,以便在lambda中调用和配置它们

    apply函数它的实现就是泛型扩展匿名函数
    之前我们已经知道如何定义一个匿名函数,现在来定义一个接受匿名函数,返回泛型类型的函数:

    fun main() {
        println(getInfo { "123" })
    }
    
    fun <T> getInfo(funp: () -> T): T {
        return funp()
    }
    

    现在我们想使getInfo函数中,支持DSL,首先需要getInfo函数支持扩展,并且它入参的匿名函数作用域可以直接使用接收者的函数和属性
    1.getInfo函数支持扩展 很简单,直接使用T.getInfo()就可以实现
    2.作用域可以直接使用接收者的函数和属性,也是扩展的特性,反观下我们上面写的扩展中,函数里使用的this就是接收者,所以扩展函数中,可以直接使用接收者的函数和属性
    想要入参的匿名函数作用域可以直接使用接收者的函数和属性,就需要匿名函数支持扩展:

    fun main() {
        println("abc".getInfo {
            this + "123"
        })
    }
    
    inline fun <T> T.getInfo(funp: T.() -> T): T {
        funp()
        return this
    }
    

    如果重复使用该方法,将会创建很多内存,所以我们需要使用inline关键字

    相关文章

      网友评论

          本文标题:kotlin--扩展

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