美文网首页
Kotlin---标准扩展函数

Kotlin---标准扩展函数

作者: None_Ling | 来源:发表于2018-12-03 16:19 被阅读8次

    介绍

    除了自定义扩展之外,Kotlin中也定义了很多的扩展函数,而这些扩展函数的接收类型是范型,也就是所有对象都可以使用。这些标准的扩展函数都放在了Standard.kt中。

    从Kotlin的语言介绍中,可以知道,Kotlin在空指针以及null对象的控制、语句表达上有很多优势,很多优势也来源于Kotlin的扩展函数的支持。

    接下来会介绍:

    • let
    • apply
    • run
    • takeIf
    • takeUnless
    • with

    也会看看,这些函数是如何让空对象的代码更加优雅的表达。

    let函数

    首先来详细介绍一下let函数的定义,以及它是如何运行的。

    /**
     * Calls the specified function [block] with `this` value as its argument and returns its result.
     */
    @kotlin.internal.InlineOnly
    public inline fun <T, R> T.let(block: (T) -> R): R {
        contract {
            callsInPlace(block, InvocationKind.EXACTLY_ONCE)
        }
        return block(this)
    }
    
    1. 函数定义:
    public inline fun <T, R> T.let(block: (T) -> R): R {
    
    • 使用inline关键字来标志这个函数是一个内联函数
    • <T,R>代表函数参数范型
    • T.let代表它是一个扩展函数,而接收参数是一个泛型
    • block:(T)->R代表函数的参数是一个代码块,而这个代码块接收参数T,并且返回R类型的对象
    • :R代表整个let函数返回类型是R类型

    其中很重要的一个概念是:Kotlin中,所有的东西都是对象,所以代码块也是一个对象,可以使用变量引用。

    1. 函数体:
    contract {
            callsInPlace(block, InvocationKind.EXACTLY_ONCE)
    }
    return block(this)
    
    • contract代码块:主要为了告诉编译器,Lambda表达式会马上执行,并且只执行一次,因为在编译器编译的时候会对某些变量判空时,判断是否可以编译通过并且运行。
    • block(this):执行代码块中的代码,并且将调用扩展函数的对象作为参数传入,返回结果

    let函数举例

    例如下面的函数,如果student不为空的话,则会打印名字和年龄。

    fun acceptStudent(student: Person?) {
            student?.let {
                println("Student Name:${it.mName}")
                println("Student Age:${it.mAge}")
            }
    }
    

    而如果这段代码用Java写的话,则是

    if(student!=null) {
        println("student name:"+student.mName);
        println("student age:"+student.mAge)
    }
    

    apply函数

    apply函数的定义如下:

    /**
     * Calls the specified function [block] with `this` value as its receiver and returns `this` value.
     */
    @kotlin.internal.InlineOnly
    public inline fun <T> T.apply(block: T.() -> Unit): T {
        contract {
            callsInPlace(block, InvocationKind.EXACTLY_ONCE)
        }
        block()
        return this
    }
    

    可以看到它和let函数差不多,只有一些区别:

    • block代码块中没有参数,仅仅只执行代码块的代码,但是可以使用this关键字来指向本对象
    • 函数的返回值是this,而block代码块没有返回值

    因为它返回的this,也可以配合let扩展函数来使用

    fun acceptStudent(student: Person?) {
            student?.apply {
                println("Apply Name...${this.mName}")
            }.let {
                println("let Age...${it?.mAge}")
            }
        }
    

    run函数

    run函数的原型是:

    /**
     * Calls the specified function [block] with `this` value as its receiver and returns its result.
     */
    @kotlin.internal.InlineOnly
    public inline fun <T, R> T.run(block: T.() -> R): R {
        contract {
            callsInPlace(block, InvocationKind.EXACTLY_ONCE)
        }
        return block()
    }
    

    可以看到,这个函数会执行代码块中的代码,并且将代码块执行的结果作为返回值返回。

    例如:
    gardenPlantTest函数中,在run代码块中打印完字符串plant,如果plant不为空返回字符串长度,否则返回0,而result中保存的也就是代码块中返回的字符串长度

    class GardenPlant {
        lateinit var plant: String;
    
        fun gardenPlantTest() {
            var result = plant.run {
                println("Plant String...$this")
                plant?.length
            }
            println("Plant Length:$result")
        }
    }
    

    takeIf函数

    takeIf的函数原型:
    将扩展对象T作为参数,执行predicate代码块的代码,如果在代码块中返回true,则返回对象T,如果返回false,则返回null

    /**
     * Returns `this` value if it satisfies the given [predicate] or `null`, if it doesn't.
     */
    @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
    }
    

    例如:
    如果plant字符串大于10,就可以采用,如果不行的话,则返回null,下面的代码块中只是表示可以在代码块中使用if等条件判断语句,只要最后返回的结果是boolean值就可以。

    class GardenPlant {
        lateinit var plant: String;
    
        fun gardenPlantTest() {
            val filetrPlant = plant.takeIf {
                if (plant.length > 10) {
                    plant.length > 10
                } else {
                    plant.length < 10
                }
            }
            println("Plant String Length >9 :$filetrPlant")
        }
    }
    

    在代码块中返回值,不能使用return关键字,因为return关键字会返回整个函数,而不是代码块

    takeUnless函数

    takeUnless函数原型如下:
    takeIf不一样的是,返回的取值取反,来进行判断是否采用。

    /**
     * Returns `this` value if it _does not_ satisfy the given [predicate] or `null`, if it does.
     */
    @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
    }
    

    with函数

    with函数不是一个扩展函数,它的原型如下:
    这个函数主要会接收一个对象,然后调用该对象的扩展代码块,然后返回代码块中的值。

    /**
     * Calls the specified function [block] with the given [receiver] as its receiver and returns its result.
     */
    @kotlin.internal.InlineOnly
    public inline fun <T, R> with(receiver: T, block: T.() -> R): R {
        contract {
            callsInPlace(block, InvocationKind.EXACTLY_ONCE)
        }
        return receiver.block()
    }
    

    例如:
    plant对象中替换完字符后,返回length,并且赋值给plantLength

    class GardenPlant {
        lateinit var plant: String;
    
        fun gardenPlantTest() {
            var plantLength = with(plant) {
                replace('w', 'r')
                length
            }
        }
    }
    

    相关文章

      网友评论

          本文标题:Kotlin---标准扩展函数

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