Apply

apply函数可看作一个配置函数,可以传入一个接收者,然后调用一系列函数来配置它以便使用,如果提供lambda给apply函数执行,它会返回配置好的接受者

val file1 = File("/User/geowin/hello.txt")
file1.apply { // this: File
setWritable(true)
setReadable(true)
setExecutable(false)
}

可以看到,调用一个个函数类配置接受者时,变量名就省略了,这是因为,在lambda表达式中,apply能让每个配置函数都作用于接受者,这种行为有时又叫做相关作用域,因为lambda表达式里的所有函数调用都是针对接收者的,或者说,它们是针对接受者的隐式调用.

let

let函数能使某个变量作用于lambda表达式里,让it关键字能引用它。let与apply比较,let会把接受者传给lambda,而apply什么都不传,匿名函数执行完,apply会返回当前接受者,而let会返回lambda的最后一行

fun main() {
val result = listOf(5, 4, 3, 2, 1).first().let {
it * it
}
println(result)
println(greeting(null)) // name is null
println(greeting("Jack")) // Welcome,Jack.
}

fun greeting(name: String?): String {
return name?.let { "Welcome,$name." } ?: "name is null"
}

run

光看作用域行为,run和apply差不多,但与apply不同,run函数不返回接收者,run返回的lambda结果,也就是true或者false。

val file = File("/Users/geowin/Downloads/hello.txt")
val run: Boolean = file.run { //this: File
readText().contains("hell1o")
}
println(run)

with

​ with函数是run的变体,他们的功能行为是一样的,但with调用方式不同,调用with时需要值参作为第一个参数传入

val run = "A new Version".run {
length > 10
}
println(run) //true

val with = with("old") {
length > 10
}
println(with) //false

also

also函数和let函数功能相似,和let一样,also也是把接受者作为值参传给lambda,但有一点不同:also返回接受者对象,而let返回lambda结果。因为这个差异,also尤其适和针对同一原始对象,利用副作用做事,既然also返回的是接受者对象,你就可以基于原始接受者对象执行额外的链式调用

var fileContents:List<String>
val also:File = File("D://hello.txt")
.also {//it: File
println(it.name)
}.also {//it: File
fileContents = it.readLines()
}
println(fileContents)

takeIf

和其他标注函数有点不一样,takeIf函数需要判断lambda中提供的条件表达式,给出true或false结果,如果判断是true,从takeIf函数返回接受者对象,如果是false,则返回null。如果需要判断某个条件是否满足,再决定是否可以赋值变量或者执行某项任务,takeIf就非常有用,概念上讲,takeIf函数类似于if语句,但它的优势是可以直接在对象实例上调用,避免了临时变量赋值的麻烦

val readText:String? = File("D://hello.txt")
.takeIf { it.exists() && it.canRead() }
?.readText()
println(readText)

takeUnless

takeIf辅助函数takeUnless,只有判断你给定的条件结果是false时,takeUnless才会返回返回原始接受者对象。

val text = File("D://hello.txt")
.takeUnless { it.isHidden }
?.readText()
println(text)