Kotlin学习笔记(10)--作用域函数
作用域函数
Kotlin 的作用域函数(Scope Functions)是一组高阶函数,主要的作用是简化代码结构、从而提高可读性和可维护性。Kotlin 提供了五种主要的作用域函数:let、run、with、apply 和 also。每种函数都有其独特的使用场景和返回值,选择合适的作用域函数可以使代码更加简洁优雅。
let 函数
定义和用途
- 定义:
let函数用于在一个对象的上下文中执行代码块,并返回代码块的结果。 - 用途:
- 处理可空对象:避免显式的非空检查。
- 限制变量作用域:在局部范围内使用变量,避免污染外部作用域。
- 链式调用:在链式调用中插入操作步骤。
- 转换对象:将对象转换为另一种类型。
基本语法
val result = object.let {
// 对 object 进行操作
it.someOperation()
}
object:需要操作的对象。it:let函数的默认参数,代表传入的对象。result:let函数的返回值。
返回值
let函数返回lambda表达式的最后一行结果,这使得它非常适合在链式调用中使用。
常见用法
处理可空对象
//不使用let函数
kotlin
fun printNameLength(name: String?) {
if (name != null) {
println("Name length: ${name.length}")
}
}
fun main() {
val name: String? = "Kotlin"
printNameLength(name)
}
// 使用let函数
fun printNameLength(name: String?) {
name?.let {
println("Name length: ${it.length}")
}
}
fun main() {
val name: String? = "Kotlin"
printNameLength(name)
}
- 简洁性:使用
let减少了显式的非空检查,使代码更加简洁。
限制变量作用域
//不使用let函数
fun calculateArea(radius: Double): Double {
val pi = 3.14159
val area = pi * radius * radius
return area
}
fun main() {
val radius = 5.0
val area = calculateArea(radius)
println("Area: $area")
}
// 使用let函数
fun calculateArea(radius: Double): Double {
return radius.let { r ->
val pi = 3.14159
pi * r * r
}
}
fun main() {
val radius = 5.0
val area = calculateArea(radius)
println("Area: $area")
}
- 作用域控制:使用
let将变量pi的作用域限制在let块内,避免了在整个函数中都可见。
链式调用中的中间操作
//不使用let函数
fun processString(str: String): String {
val trimmed = str.trim()
val uppercased = trimmed.toUpperCase()
return uppercased
}
fun main() {
val result = processString(" Kotlin ")
println(result) // 输出: KOTLIN
}
// 使用let函数
fun processString(str: String): String {
return str.trim().let { it.toUpperCase() }
}
fun main() {
val result = processString(" Kotlin ")
println(result) // 输出: KOTLIN
}
- 链式调用:使用
let可以在链式调用中插入操作步骤,避免中间变量的显式声明。
转换对象类型
//不使用let函数
fun parseNumber(str: String): Int? {
val number = str.toIntOrNull()
if (number != null) {
return number
}
return null
}
fun main() {
val number = parseNumber("123")
println(number) // 输出: 123
}
// 使用let函数
fun parseNumber(str: String): Int? {
return str.toIntOrNull()?.let { it } //返回自身对象
}
fun main() {
val number = parseNumber("123")
println(number) // 输出: 123
}
- 简化逻辑:使用
let简化了对可空对象的处理逻辑。
在对象初始化时执行操作
//不使用let函数
data class User(var name: String, var age: Int)
fun createUser(name: String, age: Int): User {
val user = User(name, age)
// 执行一些操作
println("User created: $user")
return user
}
fun main() {
val user = createUser("Alice", 30)
}
// 使用let函数
data class User(var name: String, var age: Int)
fun createUser(name: String, age: Int): User {
return User(name, age).let {
// 执行一些操作
println("User created: $it")
it
}
}
fun main() {
val user = createUser("Alice", 30)
}
注意事项
- 避免过度使用:虽然
let函数非常有用,但过度使用可能导致代码难以理解。应根据具体场景合理使用。 - 变量命名:
let函数的默认参数名是it,在需要更明确的语义时,可以显式命名参数。
val length = name?.let { nonNullName ->
println("Name is $nonNullName")
nonNullName.length
}
with 函数
定义和用途
- 定义:
with函数用于在特定对象的上下文中执行一段代码块,从而简化代码结构,提高可读性。 - 用途:适用于对同一个对象执行多项操作,尤其是需要对对象进行配置或批量操作时。
基本语法
with(receiver) {
// 在这里可以直接访问 receiver 的成员
}
receiver:要在其上下文中执行代码块的对象。- 代码块内可以直接访问
receiver的成员,无需重复引用。
常见用法
配置 StringBuilder
// 不使用 with
fun buildStringWithoutWith(): String {
val stringBuilder = StringBuilder()
stringBuilder.append("Hello, ")
stringBuilder.append("World!")
stringBuilder.append(" Kotlin is awesome.")
return stringBuilder.toString()
}
// 使用 with
fun buildStringWithWith(): String {
val stringBuilder = StringBuilder()
with(stringBuilder) {
append("Hello, ")
append("World!")
append(" Kotlin is awesome.")
}
return stringBuilder.toString()
}
初始化一个自定义对象
data class Person(var name: String = "", var age: Int = 0, var address: String = "")
// 不使用 with
fun createPersonWithoutWith(): Person {
val person = Person()
person.name = "张三"
person.age = 25
person.address = "北京市"
return person
}
// 使用 with
fun createPersonWithWith(): Person {
val person = Person()
with(person) {
name = "张三"
age = 25
address = "北京市"
}
return person
}
处理集合数据
// 不使用 with
fun processListWithoutWith(numbers: MutableList<Int>): MutableList<Int> {
numbers.removeIf { it < 0 }
numbers.sort()
numbers.forEach { println(it) }
return numbers
}
// 使用 with
fun processListWithWith(numbers: MutableList<Int>): MutableList<Int> {
with(numbers) {
removeIf { it < 0 }
sort()
forEach { println(it) }
}
return numbers
}
构建复杂的对象
class Car {
var brand: String = ""
var model: String = ""
var year: Int = 0
fun startEngine() {
println("Engine started.")
}
fun stopEngine() {
println("Engine stopped.")
}
}
// 不使用 with
fun buildCarWithoutWith(): Car {
val car = Car()
car.brand = "Toyota"
car.model = "Camry"
car.year = 2021
car.startEngine()
return car
}
// 使用 with
fun buildCarWithWith(): Car {
val car = Car()
with(car) {
brand = "Toyota"
model = "Camry"
year = 2021
startEngine()
}
return car
}
run 函数
定义和用途
- 定义:
run函数结合了let和with的功能,用于在一个代码块中执行一系列操作,并返回代码块的结果。 - 用途:适用于对象初始化、配置以及需要计算返回值的场景。
示例
// 不使用 run 作用域函数
val builder = StringBuilder()
builder.append("Hello, ")
builder.append("World!")
builder.append(" Kotlin")
println(builder.toString())
// 使用 run 作用域函数
val builder = StringBuilder()
val st = builder.run {
append("Hello, ") //相当于 builder.append(...)
append("World!")
append(" Kotlin")
toString() // 返回结果
}
println(st)
}
apply 函数
定义和用途
- 定义:
apply函数主要用于对对象进行初始化或配置,使代码更加简洁和易读。它通过在对象的上下文中执行代码块,并返回该对象本身,从而实现链式调用和简化对象配置。 - 用途:常用于对象的配置和初始化,特别是在构建对象时设置多个属性。
基本语法
val obj = YourClass().apply {
// 在这里配置对象的属性或调用方法
}
常见用法
对象初始化
// 不使用 apply 函数
class Person {
var name: String = ""
var age: Int = 0
}
fun main() {
val person = Person()
person.name = "张三"
person.age = 25
println("姓名: ${person.name}, 年龄: ${person.age}")
}
// 使用 apply 函数
class Person {
var name: String = ""
var age: Int = 0
}
fun main() {
val person = Person().apply {
name = "张三"
age = 25
}
println("姓名: ${person.name}, 年龄: ${person.age}")
}
配置 StringBuilder
// 不使用 apply 函数
val builder = StringBuilder()
builder.append("Hello")
builder.append(", ")
builder.append("World")
builder.append("!")
val result = builder.toString()
println(result)
// 使用 apply 函数
val result = StringBuilder().apply {
append("Hello")
append(", ")
append("World")
append("!")
}.toString()
println(result)
链式调用
// 不使用 apply 函数
val list = mutableListOf<Int>()
list.add(1)
list.add(2)
list.add(3)
list.add(4)
list.add(5)
println(list)
// 使用 apply 函数
val list = mutableListOf<Int>().apply {
add(1)
add(2)
add(3)
add(4)
add(5)
}
println(list)
also 函数
定义与用途
- 定义:
also的主要作用是在链式调用中执行一些附加操作,同时返回原始对象。这使得代码更加简洁和可读。 - 用途:
- 对象初始化后执行一些操作:如日志记录、打印调试信息等。
- 在链式调用中添加额外的步骤,而不影响原始对象的传递。
常见用法
对象初始化
class Person {
var name: String = ""
var age: Int = 0
}
// 不使用 also 函数
fun main() {
val person = Person()
person.name = "张三"
person.age = 25
println("Person: name=${person.name}, age=${person.age}")
}
// 使用 also 函数
fun main() {
val person = Person().also {
it.name = "张三"
it.age = 25
}
println("Person: name=${person.name}, age=${person.age}")
}
链式调用中的附加操作
data class User(var name: String, var age: Int)
// 不使用 also 函数
fun main() {
val user = User("李四", 30)
println("创建用户: $user")
user.age += 1
println("用户年龄更新后: $user")
}
// 使用 also 函数
fun main() {
val user = User("李四", 30).also {
println("创建用户: $it")
}.also {
it.age += 1
println("用户年龄更新后: $it")
}
}
- 使用
also:通过链式调用,将打印和属性更新操作嵌入到对象创建的过程中,使逻辑更加连贯。
调试和日志记录
// 不使用 also 函数
fun calculateSum(a: Int, b: Int): Int {
val sum = a + b
println("计算 $a + $b = $sum")
return sum
}
fun main() {
val result = calculateSum(5, 10)
println("结果是 $result")
}
// 使用 also 函数
fun calculateSum(a: Int, b: Int): Int {
return (a + b).also { sum ->
println("计算 $a + $b = $sum")
}
}
fun main() {
val result = calculateSum(5, 10).also {
println("结果是 $it")
}
}
- 使用
also:通过also在计算结果的同时进行打印,使代码更为简洁。
集合操作中的 also
// 不使用 also 函数
fun main() {
val numbers = mutableListOf(1, 2, 3)
numbers.add(4)
println("列表内容: $numbers")
}
// 使用 also 函数
fun main() {
val numbers = mutableListOf(1, 2, 3).also {
it.add(4)
println("列表内容: $it")
}
}
作用域函数比较
| 函数 | 接收者(Receiver) | 返回值(Return Value) | 常见用法 |
|---|---|---|---|
let |
it |
Lambda 的结果 | 处理非空对象、链式调用 |
run |
this |
Lambda 的结果 | 对象配置、计算结果 |
with |
this |
Lambda 的结果 | 操作对象,尤其是多个属性 |
apply |
this |
对象本身 | 对象初始化、配置 |
also |
it |
对象本身 | 附加操作、日志记录 |

浙公网安备 33010602011771号