美文网首页
Kotlin中的内联函数、扩展函数、语法糖

Kotlin中的内联函数、扩展函数、语法糖

作者: 千夜零一 | 来源:发表于2021-06-28 11:31 被阅读0次

    内联函数

    public inline fun <T> T.apply(block: T.() -> Unit): T { block(); return this }

    这个内联函数,是一个关于T的扩展函数。

    为什么要用内联函数?

    内联函数用inline修饰;在使用高阶函数时会带来一些运行时的效率损失:每一个函数都是一个对象,并且会得到一个闭包;inline函数编译器会将函数编译成执行的代码块,从而避免了函数频繁的压栈和出栈. 我们可以看到Kotlin的源码中,尤其是标准库,大量使用了内联函数,内联函数会是性能有所提升; 所以在我们开发中,一些工具性函数,推荐inline函数。

    扩展函数

    给类的方法做扩充,新增方法,而又不影响类的本身。

    class DogKt {
        fun run() = "狗会跑"
        fun cry() = "狗会汪汪"
    }
    
    private fun DogKt.order() = "扩展功能-》狗听从指令"
    
    
    @Test
    fun main() {
        var ex = DogKt()
        println(ex.run())
        println(ex.cry())
        println(ex.order())  //此时order函数就是扩展函数
        /**
         * 打印结果:
         * I/System.out: 狗会跑
         * I/System.out: 狗会汪汪
         * I/System.out: 扩展功能-》狗听从指令
         */
    }
    

    高阶函数

    高阶函数是将【函数】用作 参数 或 返回值 的函数。

    将 Android 里点击事件的监听用 Kotlin 来实现,它就是一个典型的高阶函数

    //                      函数作为参数的高阶函数
    //                              ↓
    fun setOnClickListener(l: (View) -> Unit) { ... }
    

    系统标准高阶函数又被称为"语法糖",他们都是内联函数

    介绍

    Kotlin - 函数式编程
    Kotlin的语法糖放在Standard.kt文件中,一共8个🍬。

    run

    (1)第一种

    @kotlin.internal.InlineOnly
    public inline fun <R> run(block: () -> R): R {
        contract {
            callsInPlace(block, InvocationKind.EXACTLY_ONCE)
        }
        return block()
    }
    
    //第一种用法:相当于 r = "xxx"赋值操作
    var r1 = kotlin.run { "xxxxx" }
    

    (2)第二种

    @kotlin.internal.InlineOnly
    public inline fun <T, R> T.run(block: T.() -> R): R {
        contract {
            callsInPlace(block, InvocationKind.EXACTLY_ONCE)
        }
        return block()
    }
    
    //第二种用法:类似于 扩展函数
    var r2 = "a".run {
        this.plus("b")
    }
    

    let

    @kotlin.internal.InlineOnly
    public inline fun <T, R> T.let(block: (T) -> R): R {
        contract {
            callsInPlace(block, InvocationKind.EXACTLY_ONCE)
        }
        return block(this)
    }
    
    //定义:fun <T, R> T.let(block: (T) -> R): R
    //功能:调用对象(T)的let函数,则该对象为函数的参数。在函数内可以通过 it 指代该对象。返回值为函数的最后一行或指定return表达式。
    //类似于run,但let在使用中可用于空安全验证,变量?.let{}
    val l = "a".let {
        it.plus("b")
    }
    l?.let {
        //当 l 不为null时代码执行此处
    }
    

    with

    @kotlin.internal.InlineOnly
    public inline fun <T, R> with(receiver: T, block: T.() -> R): R {    
    contract {        callsInPlace(block, InvocationKind.EXACTLY_ONCE)    }    
      return receiver.block()
    }
    
     /**  
    * with:跟run 类似  
    */ 
    val w = with("a"){     this.plus("b") } 
    //定义:fun <T, R> with(receiver: T, block: T.() -> R): R 
    //功能:将对象作为函数的参数,在函数内可以通过 this指代该对象。返回值为函数的最后一行或return表达式。 
    var paint1 = Paint() 
    paint1.color = Color.BLACK 
    paint1.strokeWidth = 1.0f 
    paint1.textSize = 18.0f 
    paint1.isAntiAlias = true 
    //使用with后: 
    var paint2 = Paint() 
    with(paint2) {     
        color = Color.BLACK     
        strokeWidth = 1.0f     
        textSize = 18.0f    
        isAntiAlias = true 
    }
    

    apply

    @kotlin.internal.InlineOnly
    public inline fun <T> T.apply(block: T.() -> Unit): T {    
    contract {        callsInPlace(block, InvocationKind.EXACTLY_ONCE)    }    
        block()    
        return this
    }
    
    /** 
    * apply 
    */
    //定义:fun T.apply(block: T.() -> Unit): T
    //功能:调用对象的apply函数,在函数范围内,可以任意调用该对象的任意方法,并返回该对象。
    //跟run类似,但不是返回block()而是返回自身类型,一般用于对象重新赋值情景
    var paint = Paint()
    paint.textSize = 14.0f
    paint.color = Color.WHITE
    paint.isAntiAlias = false
    //使用apply后:
    var painta = Paint().apply {    
    textSize = 14.0f    
    color = Color.WHITE    
    isAntiAlias = false
    }
    

    also

    @kotlin.internal.InlineOnly@SinceKotlin("1.1")
    public inline fun <T> T.also(block: (T) -> Unit): T {           
    contract {        callsInPlace(block, InvocationKind.EXACTLY_ONCE)    }         
        block(this)         
        return this
    }
    
     /**  
    * also : 跟let 类似  
    */ 
    val a = "a".also {     it.plus("b") } 
    //定义:fun  T.also(block: (T) -> Unit): T 
    //功能:调用对象的also函数,在函数块内可以通过 it 指代该对象,返回值为该对象本身。(注意其和let函数的区别,let返回的是最后一行,also返回的是对象本身) 
    //实例:需要返回对象本身(this)的情况下,例如建造者模式。
    

    takeIf

    @kotlin.internal.InlineOnly@SinceKotlin("1.1")
    public inline fun <T> T.takeIf(predicate: (T) -> Boolean): T? {         
    contract {        callsInPlace(predicate, InvocationKind.EXACTLY_ONCE)    }         return if (predicate(this)) this else null}
    
    //定义:fun T.takeIf(predicate: (T) -> Boolean): T?
    //功能:传递一个函数参数,如果函数结果为true,返回T对象,否则返回null。//用法:/** * 一般用法var file = File("filePath")if (file.exists()) {    //do something} else {    return false}*///使用takeIf  var file = File("filePath").takeIf { it.exists() }?:return false//do something
    

    takeUnless

    @kotlin.internal.InlineOnly@SinceKotlin("1.1")
    public inline fun <T> T.takeUnless(predicate: (T) -> Boolean): T? {     
    contract {        callsInPlace(predicate, InvocationKind.EXACTLY_ONCE)    }         
    return if (!predicate(this)) this else null}
    
    //定义:fun T.takeUnless(predicate: (T) -> Boolean): T?
    //功能:与takeIf相反,参数函数返回false时返回T对象,否则返回null,这里不再举例。
    

    repeat

    @kotlin.internal.InlineOnlypublic inline fun repeat(times: Int, action: (Int) -> Unit) {            contract { callsInPlace(action) }           
    for (index in 0 until times) {        action(index)    }}
    
    //定义:fun repeat(times: Int, action: (Int) -> Unit)//功能:重复执行action函数times次,times从0开始repeat(5){ println("count:$it") }//等价于:for (i in 0..4) { println("count:$i") }   /(0..4).forEach{println("count:$it")}
    

    拓展

    contract {        callsInPlace(predicate, InvocationKind.EXACTLY_ONCE)    }
    

    这段代码几乎每个语法糖都有,他的主要存在意义就在于,要解决如下问题

    if (!x.isNullOrEmpty()) {     
        // we know that 'x != null' here        
        println(x.length)
    }
    

    假设 x 是可以为 null 的,经过 isNullOrEmpty 函数判断之后,再执行 println 函数,那么它肯定就不是 null 了,就不需要再加两个 !! 来表示 x 不为 null 了,而现在的情况是要添加 !!

    kotlin的函数式编程

    /** 
    * 形如: 
    */
    class ReceiveObject{    
        fun exec(invoke:ReceiveObject.() -> Int){}
    }
    
    /** 
    * kotlin - 函数可以当变量传参 
    */
    fun funAsArg(args:()->Int){}  
    //args 代表函数,函数无参,返回值类型为Int。
    fun funArg():Int{    return 1}
    

    相关文章

      网友评论

          本文标题:Kotlin中的内联函数、扩展函数、语法糖

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