小狮子的Kotlin学习之路(十七)
Kotlin语法糖很多人会把Kotlin里面的很多语法,都称作Kotlin语法糖,而我更倾向于把Kotlin标准库的几个非常常用且非常有用的高阶函数称作语法糖,各有所爱哈,不喜勿喷~~而我所说的就是let,with,run,apply,also。语法糖(一) let。@kotlin.internal.InlineOnlypublic inline fun <T, R> T.let(bl
Kotlin语法糖
很多人会把Kotlin里面的很多语法,都称作Kotlin语法糖,而我更倾向于把Kotlin标准库的几个非常常用且非常有用的高阶函数称作语法糖,各有所爱哈,不喜勿喷~~
而我所说的就是let,with,run,apply,also。
语法糖(一) let。
@kotlin.internal.InlineOnly
public inline fun <T, R> T.let(block: (T) -> R): R {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
return block(this)
}
以上是标准库Standard.kt中的let函数的实现。
稍作解释,它是一个泛型内联函数,函数类型符合上一篇中的A.(B) -> C这种形式。看到它的实现很简单,返回了block(this)。
因为它没有限定符,所有的对象都可以调用它。
val a = 10
a.let {
print(it)
}
当然,这样的用法体现不了它的优势,但是我们这里能说明问题就好。后面我会共享一个我针对Kotlin系列的博客,专门写的一个Android App,用Kotlin写的,有兴趣的童鞋到时候可以git pull一下。
就取一个let的例子过来。
item?.let {
context?.contentResolver?.call(
...,
Bundle()
)
}
一般情况下,let都是配合?.来调用,就是说判断调用是否为null,如果不为null的话,执行let中的代码,而let有一个隐式的参数it,就指代已经判空的非空对象。需要注意的是,let的返回值是整个表达式的最后一行(拥有多行语句的情况下)。
语法糖(二)apply。
@kotlin.internal.InlineOnly
public inline fun <T> T.apply(block: T.() -> Unit): T {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
block()
return this
}
和let一样,也是一个泛型的扩展函数类型,意味着所有的对象都可以调用它。需要注意的是,apply的返回值是this,也就是调用对象本身,而不是let中的block(this)。
password.apply {
afterTextChanged {
loginViewModel.loginDataChanged(
this.text.toString(),// This指代password.
text.toString() ///可以省略this.
)
}
login.setOnClickListener {
loading.visibility = View.VISIBLE
loginViewModel.login(username.text.toString(), text.toString())
}
}
apply中也有一个隐式参数this,指代的就是调用对象,因此在apply上下文中,如果需要使用调用对象,可以直接使用this,或者可以省略。
语法糖(三) run。
@kotlin.internal.InlineOnly
public inline fun <R> run(block: () -> R): R {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
return block()
}
@kotlin.internal.InlineOnly
public inline fun <T, R> T.run(block: T.() -> R): R {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
return block()
}
run在标准库中有两个实现,一个是run{},另一个是T.run()。
也就是说,run可以直接执行,或者使用有接收者的形式调用。如:
val a = 10
// 直接执行run.
run {
println(a)
}
CacheManager.read(CacheCons.USER)?.run { //使用T.run.
LoggedInUserView.createFromParcel(this as Parcel).also {
binding.user = it
}
} ?: run { // 直接使用run.
binding.user =
LoggedInUserView(requireContext().getString(R.string.user_alias), "")
}
和apply一样,run也有一个隐式的参数this,指代调用者或上下文this,如果直接使用run{}指代的就是当前类上下文。
run可以有返回值this,或者不返回。
语法糖(四)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,需要说明的是,also拥有一个隐式参数it,代表调用者。另外,also的返回值是调用者本身,从实现可以看出,block(this)对this进行了处理,最后返回了this。
语法糖(五) 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一样,因此它不需要依赖调用者去.它,直接在上下文中使用即可,需要注意的是,它有两个参数,第一个参数receiver,第二个参数block,而且第二个参数的调用者就是第一个参数。
从实现中也可以看出,它返回的是第一个参数receiver.block()。
一般情况下,使用with的场景比较少。
相当于一个委托,将函数和对象传入,最终返回一个结果。
with中也有一个隐式的参数this,指代的是第一个泛型参数T。
with(context){
this.startActivity(Bundle().also {
it.putString("ext", "1")
})
// 也可以省略this。
//startActivity(Bundle().also {
// it.putString("ext", "1")
//})
}
基本最常用的语法糖就这几个啦,当然,在标准库中,有很多类似很好用的高阶函数,都可以称之为语法糖,只是这几个很常用且很有代表性。
是不是对具体的使用场景有些迷惑,在这里网上有大神针对此做出了总结,一起学习一下。

另外有兴趣的同学可以打开Standard.kt文件了解一下,比如takeIf, takeUnless等,还有基于Closable的use,简直不要太好用,有了 它,访问数据库、文件等,再也不用担心没有关闭,资源没有释放导致内存泄漏等一系列棘手问题啦。
至此,童鞋们已经可以游刃有余地使用Kotlin来写应用啦。基于Kotlin1.3,Kotlin的协程已经很稳定了,而且提供了像通道、扇入、扇出、生产者-消费者等一系列好用的能力。
下一篇,就来看看协程的魅力。因为小狮子主要做Android的,因此可能某些例子会直接使用Android中的相关代码,能说明问题就可以啦。
我建了一个QQ群(877735946),现在也没几个人=_=,有兴趣的童鞋可以加群一起学习讨论,如果我知道的,必将知无不言。
对于文章如果有描述或理解错误的,还望大神留言区多多指教,不胜感激+_+。
更多推荐


所有评论(0)