想象一下如果 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.run 和 T.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.run比T.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.let和T.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个属性特征,我们现在可以对功能进行相应的分类。基于此,我们可以在下面构建一个决策树,以帮助确定我们想要使用哪个函数,来选择我们需要的。
希望上面的决策树能够更清晰地说明功能,并简化你的决策,使你能够适当掌握这些功能的使用.
译者有话说
最后
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。
因此我收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点!不论你是刚入门Android开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门
如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门**
如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!