Kotlin之let,apply,run,with,run使用

1,173 阅读4分钟

近两年开始使用kotlin替代java来开发android项目,感觉还不错,空指针类的bug少了很多,代码也比以前要简洁;但kotlin的一些特殊语法只停留在使用阶段,很少去总结,被人问起,就只能凭印象说个大概,这次就来总结一下apply,let,run,with,run。

let

let函数是一个作用域函数,在作用域内可使用it访问对象的公共属性和方法,返回值由作用域内最后一行决定,返回值类型是Any;

let的inline+lambda结构

@kotlin.internal.InlineOnly
public inline fun <T, R> T.let(block: (T) -> R): R {
    return block(this)
}

结构分析: let函数只有block作为参数传入,并在代码块内通过it代指该对象,返回值为代码块的最后一行;

var user: TextEntity? = null
user.let {
    it?.text // 可通过it访问其公共属性和函数
    println("hello let1")
}
user?.let {
    it.text // 做非空判断,为空则不执行
    println("hello let2")
}
val result = user?.let {
    1// 最后一行作为返回值,值类型为Any
}

使用场景:

场景一:对一个对象做判空处理; 场景二:在let作用域内访问该对象的公共属性和方法;

run

run是一个作用域函数,作用域内可通过this(可简写忽略)访问其内部公共属性和方法,并将作用域最后一行作为返回值,返回值类型是Any;

run函数的inline+lambda结构

@kotlin.internal.InlineOnly
public inline fun <T, R> T.run(block: T.() -> R): R {
    return block()
}

结构分析: run函数只接受一个lambda函数作为参数,以闭包的形式返回;

var user: TextEntity? = null
user.run {
   this?.text = "hello word" // 可通过this访问其公共属性和方法
   println("hello run1")
}
user?.run {
   text = "hello word" // 做非空判断,为空则不执行
   println("hello run2")
}
val result: Int? = user?.run {
   1 // 最后一行做返回值,类型是Any
}

使用场景: 使用场景和apply类似,可用于实例的初始化,比如加载xml时的数据绑定;

apply

apply函数是一个作用域函数,作用域内使用this来访问其对象的公共属性和方法,且返回值类型是对象本身;

apply函数的inline+lambda结构

@kotlin.internal.InlineOnly
public inline fun <T> T.apply(block: T.() -> Unit): T {
    block()
    return this
}

结构分析: apply的结构和run的很相似,唯一不同的是返回结果是传入对象本身;

var user: TextEntity? = null
user.apply {
    this?.text = "hello word" //  可通过this访问其公共属性和方法
    println("hello apply1")
}
user?.apply {
    text = "hello word" // 做非空判断,为空则不执行
    println("hello apply2")
}
val result: TextEntity? = user?.apply {
    // 返回值为this(对象本身)
}

使用场景: apply一般用于对象初始化时,进行内部赋值,比如adapter初始化时设置各类触摸监听事件,或者 加载xml时,对View绑定事件和数据也会用到;

with

with函数和之前的函数都不一样,它必须将对象作为参数传递进去,作用域内可通过this访问其公共属性和方法,且作用域内代码一定会执行,并将作用域内最后一行作为返回值,返回值类型是Any(Unit的父类是Any);

with函数的inline+lambda结构

@kotlin.internal.InlineOnly
public inline fun <T, R> with(receiver: T, block: T.() -> R): R {
    return receiver.block()
}

结构分析: with函数需要将对象作为函数的参数传入,在函数块内通过this代指该对象,返回是为代码块最后一行;

var user: TextEntity? = null
with(user){
    this?.text = "hello word" // 可通过this访问其公共属性和方法
}
with(user){
    println("hello with1") // 不管对象是否为空,作用域内都会执行
}
println("hello with2")
val result = with(user) {
    1 // 作用域内最后一行作为返回值
}

使用场景: 适用于调用同一个类的多个方法时,可以省去类名重复;比如Recyclerview中onBinderViewHolder中,数据的属性映射到UI上;

also

also函数是作用域函数,作用域内可通过it访问其公共的属性和方法,返回值是对象本身;

also的inline+lambda结构

@kotlin.internal.InlineOnly
@SinceKotlin("1.1")
public inline fun <T> T.also(block: (T) -> Unit): T {
    block(this)
    return this
}

结构分析: also函数是以闭包的形式返回,返回传入对象本身;

var user: TextEntity? = null
user.also {
    it?.text = "hello word" // 可通过it访问其内部公共属性和方法
    println("hello also1")
}
user?.also {
    it.text = "hello word" // 做非空判断,为空则不执行
    println("hello also2")
}
val result = user?.also {
    // 返回值为this(对象本身),返回值和apply效果一致
}

使用场景: 可用于对象初始化赋值,比如加载xml时,为View绑定数据;

用一张图来区分