[译]掌握Kotlin中的标准库函数_ run、with、let、also和apply

想象一下如果 webview.settings 可能为空,那么下面两种方式实现如何去修改呢?

// Yack!(比较丑陋的实现方式)
with(webview.settings) {
this?.javaScriptEnabled = true
this?.databaseEnabled = true
}
}
// Nice.(比较好的实现方式)
webview.settings?.run {
javaScriptEnabled = true
databaseEnabled = true
}

在这种情况下,显然 T.run 扩展函数更好,因为我们可以在使用它之前对可空性进行检查。

2、this VS it 参数(This vs. it argument)

如果我们对比 T.runT.let 两个函数也是非常的相似,唯一的区别在于它们接收的参数不一样。下面显示了两种功能的相同逻辑。

stringVariable?.run {
println(“The length of this String is $length”)
}
// Similarly.
stringVariable?.let {
println(“The length of this String is ${it.length}”)
}

如果你查看过 T.run 函数声明,你就会注意到T.run仅仅只是被当做了 block: T.() 扩展函数的调用块。因此,在其作用域内,T 可以被 this 指代。在编码过程中,在大多数情况下this是可以被省略的。因此我们上面的示例中,我们可以在println语句中直接使用 l e n g t h ∗ ∗ 而不是 ∗ ∗ length** 而不是 ** length而不是{this.lenght}. 所以我把这个称之为传递 this参数

然而对于 T.let 函数的声明,你将会注意到 T.let 是传递它自己本身到函数中block: (T)。因此这个类似于传递一个lambda表达式作为参数。它可以在函数作用域内部使用it来指代. 所以我把这个称之为传递 it参数

从上面看,似乎T.runT.let更加优越,因为它更隐含,但是T.let函数具有一些微妙的优势,如下所示:

  • 1、T.let函数提供了一种更清晰的区分方式去使用给定的变量函数/成员与外部类函数/成员。
  • 2、例如当it作为函数的参数传递时,this不能被省略,并且it写起来比this更简洁,更清晰。
  • 3、T.let允许更好地命名已转换的已使用变量,即可以将it转换为其他有含义名称,而 T.run则不能,内部只能用this指代或者省略。

stringVariable?.let {
nonNullString ->
println(“The non null string is $nonNullString”)
}

3、返回this VS 其他类型 (Return this vs. other type)

现在,让我们看看T.letT.also,如果我们看看它的内部函数作用域,它们都是相同的。

stringVariable?.let {
println(“The length of this String is ${it.length}”)
}
// Exactly the same as below
stringVariable?.also {
println(“The length of this String is ${it.length}”)
}

然而,他们微妙的不同在于他们的返回值T.let返回一个不同类型的值,而T.also返回T类型本身,即这个。

这两个函数对于函数的链式调用都很有用,其中T.let让您演变操作,而T.also则让您对相同的变量执行操作。

简单的例子如下:

val original = “abc”
// Evolve the value and send to the next chain
original.let {
println(“The original String is $it”) // “abc”
it.reversed() // evolve it as parameter to send to next let
}.let {
println(“The reverse String is $it”) // “cba”
it.length // can be evolve to other type
}.let {
println(“The length of the String is $it”) // 3
}
// Wrong
// Same value is sent in the chain (printed answer is wrong)
original.also {
println(“The original String is $it”) // “abc”
it.reversed() // even if we evolve it, it is useless
}.also {
println(“The reverse String is ${it}”) // “abc”
it.length // even if we evolve it, it is useless
}.also {
println(“The length of the String is ${it}”) // “abc”
}
// Corrected for also (i.e. manipulate as original string
// Same value is sent in the chain
original.also {
println(“The original String is $it”) // “abc”
}.also {
println(“The reverse String is ${it.reversed()}”) // “cba”
}.also {
println(“The length of the String is ${it.length}”) // 3
}

T.also似乎看上去没有意义,因为我们可以很容易地将它们组合成一个功能块。仔细思考,它有一些很好的优点。

  • 1、它可以对相同的对象提供非常清晰的分离过程,即创建更小的函数部分。
  • 2、在使用之前,它可以非常强大的进行自我操作,从而实现整个链式代码的构建操作。

当两者结合在一起使用时,即一个自身演变,一个自我保留,它能使一些操作变得更加强大。

// Normal approach
fun makeDir(path: String): File {
val result = File(path)
result.mkdirs()
return result
}
// Improved approach
fun makeDir(path: String) = path.let{ File(it) }.also{ it.mkdirs() }

回顾所有属性特征

通过回顾这3个属性特征,我们可以非常清楚函数的行为。让我来说明T.apply函数,由于我并没有以上函数中提到过它。 T.apply的三个属性如下

  • 1、它是一个扩展函数
  • 2、它是传递this作为参数
  • 3、它是返回 this (即它自己本身)

因此,使用它,可以想象下它可以被用作:

// Normal approach
fun createInstance(args: Bundle) : MyFragment {
val fragment = MyFragment()
fragment.arguments = args
return fragment
}
// Improved approach
fun createInstance(args: Bundle)
= MyFragment().apply { arguments = args }

或者我们也可以让无链对象创建链式调用。

// Normal approach
fun createIntent(intentData: String, intentAction: String): Intent {
val intent = Intent()
intent.action = intentAction
intent.data=Uri.parse(intentData)
return intent
}
// Improved approach, chaining
fun createIntent(intentData: String, intentAction: String) =
Intent().apply { action = intentAction }
.apply { data = Uri.parse(intentData) }

函数的选用

因此,显然有了这3个属性特征,我们现在可以对功能进行相应的分类。基于此,我们可以在下面构建一个决策树,以帮助确定我们想要使用哪个函数,来选择我们需要的。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

希望上面的决策树能够更清晰地说明功能,并简化你的决策,使你能够适当掌握这些功能的使用.

译者有话说

分享读者

作者2013年java转到Android开发,在小厂待过,也去过华为,OPPO等大厂待过,18年四月份进了阿里一直到现在。

被人面试过,也面试过很多人。深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长,不成体系的学习效果低效漫长,而且极易碰到天花板技术停滞不前!

我们整理了一份阿里P7级别的Android架构师全套学习资料,特别适合有3-5年以上经验的小伙伴深入学习提升。

主要包括腾讯,以及字节跳动,阿里,华为,小米,等一线互联网公司主流架构技术。

腾讯T3架构师学习专题资料

如果你觉得自己学习效率低,缺乏正确的指导,可以一起学习交流!

我们致力打造一个平等,高质量的Android交流圈子,不一定能短期就让每个人的技术突飞猛进,但从长远来说,眼光,格局,长远发展的方向才是最重要的。

35岁中年危机大多是因为被短期的利益牵着走,过早压榨掉了价值,如果能一开始就树立一个正确的长远的职业规划。35岁后的你只会比周围的人更值钱。
《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》点击传送门,即可获取!
眼光,格局,长远发展的方向才是最重要的。

35岁中年危机大多是因为被短期的利益牵着走,过早压榨掉了价值,如果能一开始就树立一个正确的长远的职业规划。35岁后的你只会比周围的人更值钱。
《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》点击传送门,即可获取!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值