Kotlin中标准库函数(apply、let、run、with、also、takeIf、takeUnless)的使用详解

简介: Kotlin中标准库函数(apply、let、run、with、also、takeIf、takeUnless)的使用详解

一、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


目录
相关文章
|
1月前
|
安全 Kotlin
Kotlin教程笔记(23) -作用域函数
Kotlin教程笔记(23) -作用域函数
154 6
|
1月前
|
Kotlin
Kotlin教程笔记(21) -高阶函数与函数引用
Kotlin教程笔记(21) -高阶函数与函数引用
43 6
|
2月前
|
IDE 开发工具 Kotlin
Kotlin - 函数与Lambda表达式
Kotlin - 函数与Lambda表达式
47 13
|
2月前
|
IDE 开发工具 Kotlin
Kotlin教程笔记(6) - 函数与Lambda表达式
Kotlin教程笔记(6) - 函数与Lambda表达式
61 1
|
Kotlin
【Kotlin】Kotlin 构造函数 ( 主构造函数 | 主构造函数声明属性 | init 初始化代码块 | 次构造函数 | 构造函数委托 | 调用构造函数创建实例对象 )(二)
【Kotlin】Kotlin 构造函数 ( 主构造函数 | 主构造函数声明属性 | init 初始化代码块 | 次构造函数 | 构造函数委托 | 调用构造函数创建实例对象 )(二)
131 0
|
Kotlin
【Kotlin】Kotlin 构造函数 ( 主构造函数 | 主构造函数声明属性 | init 初始化代码块 | 次构造函数 | 构造函数委托 | 调用构造函数创建实例对象 )(一)
【Kotlin】Kotlin 构造函数 ( 主构造函数 | 主构造函数声明属性 | init 初始化代码块 | 次构造函数 | 构造函数委托 | 调用构造函数创建实例对象 )(一)
297 0
|
3月前
|
JSON 调度 数据库
Android面试之5个Kotlin深度面试题:协程、密封类和高阶函数
本文首发于公众号“AntDream”,欢迎微信搜索“AntDream”或扫描文章底部二维码关注,和我一起每天进步一点点。文章详细解析了Kotlin中的协程、扩展函数、高阶函数、密封类及`inline`和`reified`关键字在Android开发中的应用,帮助读者更好地理解和使用这些特性。
51 1
|
4月前
|
Android开发 开发者 Kotlin
告别AsyncTask:一招教你用Kotlin协程重构Android应用,流畅度飙升的秘密武器
【9月更文挑战第13天】随着Android应用复杂度的增加,有效管理异步任务成为关键。Kotlin协程提供了一种优雅的并发操作处理方式,使异步编程更简单直观。本文通过具体示例介绍如何使用Kotlin协程优化Android应用性能,包括网络数据加载和UI更新。首先需在`build.gradle`中添加coroutines依赖。接着,通过定义挂起函数执行网络请求,并在`ViewModel`中使用`viewModelScope`启动协程,结合`Dispatchers.Main`更新UI,避免内存泄漏。使用协程不仅简化代码,还提升了程序健壮性。
148 1
|
6月前
|
安全 Android开发 Kotlin
Android经典面试题之Kotlin延迟初始化的by lazy和lateinit有什么区别?
**Kotlin中的`by lazy`和`lateinit`都是延迟初始化技术。`by lazy`用于只读属性,线程安全,首次访问时初始化;`lateinit`用于可变属性,需手动初始化,非线程安全。`by lazy`支持线程安全模式选择,而`lateinit`适用于构造函数后初始化。选择依赖于属性特性和使用场景。**
192 5
Android经典面试题之Kotlin延迟初始化的by lazy和lateinit有什么区别?
|
5月前
|
调度 Android开发 开发者
【颠覆传统!】Kotlin协程魔法:解锁Android应用极速体验,带你领略多线程优化的无限魅力!
【8月更文挑战第12天】多线程对现代Android应用至关重要,能显著提升性能与体验。本文探讨Kotlin中的高效多线程实践。首先,理解主线程(UI线程)的角色,避免阻塞它。Kotlin协程作为轻量级线程,简化异步编程。示例展示了如何使用`kotlinx.coroutines`库创建协程,执行后台任务而不影响UI。此外,通过协程与Retrofit结合,实现了网络数据的异步加载,并安全地更新UI。协程不仅提高代码可读性,还能确保程序高效运行,不阻塞主线程,是构建高性能Android应用的关键。
75 4