Kotlin let,run,apply等扩展函数原理

kotlin基本函数的使用

高阶扩展函数

1.let函数
let的使用

在闭包内用it代替调用者,let的返回值为函数的最后一行。
let常用来做为判空后的处理

        //不用let时每次都需要对textView判空
        textView?.text = "let"
        textView?.setTextColor(Color.BLACK)
        textView?.ellipsize = TextUtils.TruncateAt.END

        textView?.let {
            it.text = "let"
            it.setTextColor(Color.BLACK)
            it.ellipsize = TextUtils.TruncateAt.END
        }
let的定义
//定义两个泛型T,R,T.let代表对任意类T添加let扩展函数,这个扩展函数的返回值为R
//参数block是一个函数且类型为(T) -> R
//由于let返回值为R且block返回值也为R,所以直接返回block函数的返回值
//调用let的是T,所以let闭包里this就代表T,block的参数为T,block应传入this,所以在block闭包内使用it即代表T
public inline fun <T, R> T.let(block: (T) -> R): R {
    return block(this)
}

上面可能有些人看不太明白,我们把泛型去了再看会发现其实挺简单的
这里定义String的扩展函数let1,返回Int类型

//去掉泛型后的let
public inline fun String.let1(block: (String) -> Int): Int {
    return block(this)
}

我们分别调用let1和let其结果是一样的

        //这里给出调用let1时的简化过程,对函数有不太理解的可以去看看上一篇文章
        var a: Int

        a = "1".let1(fun(a: String): Int {
            return a.toInt()
        })
        Log.i("kotlin fun  test2:  ", "返回值$a")

        a = "1".let1({ a ->
            a.toInt()
        })
        Log.i("kotlin fun  test2:  ", "返回值$a")

        a = "1".let1 { a ->
            a.toInt()
        }
        Log.i("kotlin fun  test2:  ", "返回值$a")

        //这里就是我们熟悉的let调用方式
        a = "1".let1 {
            it.toInt()
        }
        Log.i("kotlin fun  test2:  ", "返回值$a")

        //然后我们直接调用let
        a = "1".let {
            it.toInt()
        }
        Log.i("kotlin fun  test2:  ", "返回值$a")

以上的几个函数结果都是相同的

2.run函数

相对于let,我更喜欢使用run,一般情况下let能做的事用run也可以做,而且用run代码会更简洁。

run的使用

在闭包内用this代替调用者,run的返回值为函数的最后一行。

        //相对于let,代码简洁
        textView?.run {
            text = "run"
            setTextColor(Color.BLACK)
            ellipsize = TextUtils.TruncateAt.END
        }
run的定义

相对于let,run的改动点只有一处,由(T)换成了T.()

//定义两个泛型T,R,T.run代表对任意类T添加run扩展函数,这个扩展函数的返回值为R
//参数block是一个函数且类型为T.() -> R
//由于run返回值为R且block返回值也为R,所以直接返回block函数的返回值
//T.()代表给T添加一个匿名扩展函数,即block函数是T的匿名扩展函数,所以block函数闭包内的this即代表T
public inline fun <T, R> T.run(block: T.() -> R): R {
    return block()
}

上面注释前三行和let一样,只有最后一行有区别,这也是导致let和run差异的原因。

3.with函数

with函数在实际项目中应用很少,基本都被run代替,这里还是介绍下with函数的原理

with的使用

with用法和let、run有所不同,with不是作为扩展函数使用的,with接收一个对象,闭包内this代表传入的对象,with的返回值为函数的最后一行。

        with(textView) {
            if (this != null) {
                text = "with"
                setTextColor(Color.BLACK)
                ellipsize = TextUtils.TruncateAt.END
            }
        }
with的定义
//with和run的区别在于,run是通过扩展函数实现,with通过顶层函数实现(不借助类或对象可以直接使用)
//由于with是顶层函数,闭包内不包含上下文,所以调用block函数时需要指定T的对象进行调用,这也导致了with相对于run需要多传入一个参数T
public inline fun <T, R> with(receiver: T, block: T.() -> R): R {
    return receiver.block()
}
4.apply函数

apply和run都是项目中最常见的扩展函数,run用来返回闭包内最后一行,apply用来返回调用者对象。

apply的使用

apply最常用的有两个地方
1.给对象进行初始化赋值
2.给model进行数据判空处理

        //1
        var textView = findViewById<TextView>(R.id.btn).apply {
            text = "let"
            setTextColor(Color.BLACK)
            ellipsize = TextUtils.TruncateAt.END
        }
        //2
        userInfo?.apply {
            //userInfo不为空时要处理的内容
        }?.info?.apply {
            //info不为空时要处理的内容
        }?.title?.apply {
            //title不为空时要处理的内容
        }
class UserInfo {
    var name: String? = null
    var info: Info? = null

    class Info {
        var title: String? = null
    }
}
apply的定义
//相较于run,apply只有一个泛型,即apply是T的扩展函数,返回的也是T
//block依旧为T的匿名扩展函数,apply闭包包含T的上下文关系,直接在闭包调用block,返回this
public inline fun <T> T.apply(block: T.() -> Unit): T {
    block()
    return this
}
5.also函数

also与with一样,在实际项目中应用较少,这里也只简单介绍下

also的使用
        textView?.also {
            it.text = "also"
            it.setTextColor(Color.BLACK)
            it.ellipsize = TextUtils.TruncateAt.END
        }
also的定义
//also是T的扩展函数,所以also的闭包的上下文是T
//匿名函数block的入参为T,所以block传入this
//block是非扩展函数,所以block的闭包上下文为also的外层对象,在block的闭包里用it指向T
public inline fun <T> T.also(block: (T) -> Unit): T {
    block(this)
    return this
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容