Kotlin作用域函数及用法
前言
Kotlin 标准库包含几个函数,它们的唯一目的是在对象的上下文中执行代码块。当对一个对象调用这样的函数并提供一个lambda 表达式时,它会形成一个临时作用域。在此作用域中,可以访问该对象而无需其名称。这些函数称为作用域函数。共有以下五种:
let
、run
、with
、apply
以及also
。
以上是官网对Kotlin作用域的一个解释,读几遍是不是也不懂他意思?
从实际出发,依次展开来看看。
let
在作用域中使用(it
)来访问对象,返回值是lambda 表达式的结果。
fun main() { var name="name" println(name.let { it.length }) } 复制代码
如上操作,在{}号中,有个隐式的变量名it,在其中对name变量的任何操作都可以使用it来代替,如果在其中更改了对象的值,那么it变量是不会发生改变的。
并且最后一行的返回结果,会作为let函数的返回结果。如果最后一行没有返回值,在Kotlin中也会被kotlin.Unit来代替。
run
在作用域中使用(this
)来访问对象,返回值是lambda 表达式的结果。
fun main() { var name="name" println(name.run { println(length) "a" }) } 复制代码
如上操作,除了返回值和let一样,他的作用域变量成为了this,但是这里就发生了一个变化,对对象的操作可以不加this,直接可以调用,而let中不行,比如上面的操作,如果用let来访问length方法时,就必须是it.length,在看一个例子,
class Data(var name: String) { } fun main() { var name = "name" println(Data("dog").run { println(name) name="cat" }) println(name) } 复制代码
run还有一个非扩展方法,调用也不需要什么参数,返回值Lambda 表达式结果,如下。
fun main() { var function = { println("a") } // function() run(function) } 复制代码
在Java中,方法中写的{}会自动执行,而kotlin不会,需要手动调用,或者是run。
with
他不是扩展函数,也就是没有obj.with这种写法,而是with(obj){},然后在lambda表达式内部,可以使用(this
)访问此对象,也可以省略, 返回值是lambda 表达式结果。
with可以理解为"对于这个对象,执行以下操作"。
var name="cat" with(name){ name="dog" println(name) println(this) } 复制代码
同样,在作用域中对原对象修改后,并不影响其中的this。
apply
在作用域中使用(this
)来访问对象,返回值是是对象本身。
class Data(var name: String) { } fun main() { var name = Data("dog").apply { name = "cat" } println(name.name) } 复制代码
also
在作用域中使用(it
)来访问对象,返回值是是对象本身。
class Data(var name: String) { } fun main() { var name = Data("dog").also { it.name="cat" } println(name.name) } 复制代码
总结
看了这么多,是不是还迷迷糊糊的,这些作用域函数都非常相似,因此了解它们之间的区别很重要,我们可以从他们这两点区分。
引用上下文对象的方式
返回值
函数 | 对象引用 | 返回值 | 是否是扩展函数 |
---|---|---|---|
let | it | Lambda 表达式结果 | 是 |
also | it | 上下文对象 | mps |
run | this | Lambda 表达式结果 | 是 |
with | this | Lambda 表达式结果 | 不是:把上下文对象当做参数 |
apply | this | 上下文对象 | 是 |
run | - | Lambda 表达式结果 | 不是:调用无需上下文对象 |
最重要的就是记住返回值,因为对象引用的方式不太重要,如果你想少写代码,并且返回值需要Lambda 表达式结果,那么就使用run,如果需要本身,那就使用apply。
我们在看一个例子。
public class MainJava { public static void main(String[] args) throws IOException { BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(new FileInputStream("/home/HouXinLin/1.txt"))); String temp = null; while ((temp = bufferedReader.readLine()) != null) { System.out.println(temp); } } } 复制代码
而在Kotlin中while中又赋值又判断这种写法是错的,解决方式就需要使用作用域函数,并且接收的变量还需要设置为可空类型
fun main() { var bufferedReader = File("/home/HouXinLin/1.txt").inputStream().bufferedReader() var temp: String? while (bufferedReader.readLine().also { temp = it } != null) { println(temp) } }
作者:i听风逝夜
链接:https://juejin.cn/post/7048596405119778846