一、apply函数
apply
apply函数可以看作是一个配置函数,你可以传入一个接收者,然后调用一系列函数来配置它以便使用,如果提供lambda表达式给 apply函数执行,它会返回配置好的接收者。
可以看到,调用一个个函数类配置接收者时,变量名就省略掉了。
这是因为,在lambda表达式里,apply能让每个配置函数都作用于接收者,
这种行为有时又叫相关作用域,因为lambda表达式里的所有函数调用都是针对接收者的,或者说,它们是针对接收者的隐时调用。
fun main() { val file1 = File("D:\\android.txt") file1.setReadable(true)//可读 file1.setWritable(true)//可写 file1.setExecutable(false)//不能执行 /** * apply * apply函数可以看作是一个配置函数,你可以传入一个接收者, * 然后调用一系列函数来配置它以便使用,如果提供lambda表达式给 * apply函数执行,它会返回配置好的接收者。 * * 可以看到,调用一个个函数类配置接收者时,变量名就省略掉了。 * 这是因为,在lambda表达式里,apply能让每个配置函数都作用于接收者, * 这种行为有时又叫相关作用域,因为lambda表达式里的所有函数调用都是针对接收者的, * 或者说,它们是针对接收者的隐时调用。 */ val file2 = File("D:\\android.txt").apply { setReadable(true) setWritable(true) setExecutable(false) } }
二、let函数
fun main() { /** * let * let函数能使某个变量作用于其lambda表达式里,让it关键字能引用它,let与apply * 比较,let会把接收者传给lambda,而apply什么都不传,匿名函数执行完,apply会返回当前接收者 * 而let会返回lambda的最后一行。 */ val result = listOf(3, 2, 1).first().let { it * it } println(result) val firstElement = listOf(3, 2, 1).first() val result1 = firstElement * firstElement println(result1) println(formatGreeting(null)) println(formatGreeting("android")) } /** * 使用let函数与安全调用操作符,空合并操作符一起使用 */ fun formatGreeting(guestName: String?): String { return guestName?.let { "Welcome,$it." } ?: "What's your name?" } fun formatGreeting1(guestName: String?): String { return if (guestName != null) { "Welcome $guestName" } else { "What's your name?" } }
输出结果:
9 9 What's your name? Welcome,android.
三、run函数
fun main() { /** * run函数 * 光看作用域行为,run和apply差不多,但与apply不同,run函数不返回接收者,run返回的是lambda表达式 * 也就是true或者false,都是返回匿名函数的最后一行,不只是true或false * * run也能用来执行函数引用 */ var file = File("D:\\android.txt") val result = file.run { readText().contains("great") } println(result) val result1 = "The people's Republic of China.".run(::isLong) println(result1) "The people's Republic of China.".run(::isLong).run(::showMessage).run(::println) } fun isLong(name: String) = name.length >= 10 fun showMessage(isLong: Boolean): String { return if (isLong) { "Name is too long." } else { "Please rename" } }
输出结果:
true true Name is too long.
四、with函数
fun main() { val result1 = "The people's Republic of China.".run { length >= 10 } println(result1) /** * with函数是run的变体,它们的功能行为是一样的,但with的调用方式不一样,调用with * 时需要值参作为其第一个参数传入 */ val result2 = with("The people's Republic of China.") { length >= 10 } println(result2) }
输出结果:
true true
五、also函数的使用
also函数和let函数功能相似,和let一样,also也是把接收者作为值参传给lambda
但有一点不同:also返回接收者对象,而let返回lambda结果。
因为有这个差异,also尤其适合针对同一原始对象,利用副作用做事,既然also返回的是接收者对象
你就可以基于原始接收者对象执行额外的链式调用。
fun main() { /** * also * also函数和let函数功能相似,和let一样,also也是把接收者作为值参传给lambda * 但有一点不同:also返回接收者对象,而let返回lambda结果。 * 因为有这个差异,also尤其适合针对同一原始对象,利用副作用做事,既然also返回的是接收者对象 * 你就可以基于原始接收者对象执行额外的链式调用。 */ var fileContents: List<String> val file = File("D://android.txt").also { println(it.name) }.also { fileContents = it.readLines() } println(fileContents) }
输出结果如下:
android.txt [great ssss]
六、takeIf函数
fun main() { /** * takeIf * 和其他标准函数有点不一样,takeIf函数需要判断lambda中提供的条件表达式,给出true或false结果 * 如果判断结果为true,从takeIf函数返回接收者对象,如果是false,则返回null。 * 如果需要判断某个条件是否满足,再决定是否可以赋值变量或执行某项任务,takeIf就非常有用, * 概念上讲,takeIf函数类似于if语句,但它的优势是可以直接在对象实例上调用,避免了临时变量 * 赋值的麻烦。 */ val result = File("D:\\android.txt").takeIf { it.exists() && it.canRead() }?.readText() println(result) //不同takeIf函数 val file = File("D:\\android.txt") val result2 = if (file.exists() && file.canRead()) { file.readText() } else { null } println(result2) }
输出结果:
great ssss great ssss
七、takeUnless函数
fun main() { /** * takeIf的辅助函数takeUnless,只有判断你给定的条件结果是false时,takeUnless才会 * 返回原始接收者对象 */ val result = File("D:\\android.txt") .takeUnless { it.isHidden }?.readText() println(result) }
输出结果:
great ssss