新语言还是多练习的好,不然怎么会遇到问题呢。
遇到的问题
今天依然尝试用 kotlin 写写 demo,加载图片的时候写了下面这段代码。
1 | fun loadImageLikeJava(imageUrl: String) { |
相比正常用 Java 写的逻辑,代码并没有少多少,只是类型推断跟 lambda 让代码看起来干净不少。可是如果这么用 kotlin 并没有多少好,“能不能让代码再少点”,想了一会就改成这样:
1 | fun loadImage(imageUrl: String) { |
用上了 let
跟 also
之后,Callback 里就只剩下一句。
Kotlin 标准库里的这几个内置函数特别好用,但跟其他几个函数一起的话经常容易让人搞混,于是在这里一起总结一下以做记录。
关于 let, also, run, with, apply
先看几个函数的签名:
1 | public inline fun <T, R> T.let(block: (T) -> R): R = block(this) |
T.apply()
跟T.also()
是类似的,他们都可以像 Builder 模式一样链式调用。但T.apply()
的参数是T.() -> Unit
, 即要执行的 block 就像是在 T 内部一样,如果需要调用 T 的方法不需要 it 指明,而T.also()
就需要。T.let()
跟T.run()
也是类似的,执行函数后返回一个值,就像是 L map R 一样,但T.run()
跟T.apply()
类似,block 都像是在 T 内部一样。with()
跟run()
跟上面四个函数都不大一样,这两个函数不需要在 T 上调用。run()
是 block 返回一个值 R,跟Callable
有点像,但直接new Callable()
没法直接返回一个值,只能是一个Callable
。-
with()
则是这里面唯一一个接受两个参数的(虽然经过 lambda 表达式的简化之后看起来可以像是一个),第一个参数是接受调用的参数,第二个参数是作用在第一个参数上的方法。这跟T.apply()
非常像,但T.apply()
返回的是自身,with()
执行结束后可以返回其他值。
简单点记的话是不是可以这样:`also let it go, apply run like inside`
let 一个常见用法
今天在调用一个 nullable 的对象的时候出现了 kotlin 的 smartcast 「失效」 的情况:
1 | var loadDrawable: Drawable = null |
我本以为经过 != null
的判断,loadDrawable
已经不可能会空,但 IDE 是这么提示的:「无法智能地将 BitmapDrawable? 转换为 BitmapDrawable,因为 loadDrawable 是可变属性,在调用的时候有可能被改变」。仔细想想确实也是,虽然我这里没有没有操作,但一旦有多线程操作,loadDrawable
有可能为 null。如果真的确定不会为 null 或者只会在同一个线程内修改,强制用 loadDrawable!!
是可以的,但有没有更优雅点的方式呢?
有的,就是用 let
(also
也可以,但这里并不需要返回 this)。
1 | fun loadFinish() { |
这样编译器就不会再提醒 smart cast 失败了。
参考 let vs if not null