Kotlin 中的作用域函数

作用域函数在 Kotlin 中非常有用,可以帮助我们管理代码并编写清晰易读的代码。

什么是作用域函数?

Kotlin 标准库中包含几个函数,其唯一目的是在对象的上下文中执行一段代码块。当我们在对象上调用这样的函数并提供一个 lambda 表达式时,它形成了一个临时作用域。在这个作用域中,我们可以通过对象的属性和函数来访问该对象,而无需使用对象的名称。这些函数被称为作用域函数。Kotlin 中共有五个作用域函数:letrunwithapply 和 also

关于 this 和 it

  • this:在 runwith 和 apply 函数中,我们可以使用 lambda 接收者关键字 this 来引用上下文对象。因此,在它们的 lambda 表达式中,可以像在普通类函数中一样访问对象。在大多数情况下,当访问接收者对象的成员时,我们可以省略 this,从而使代码更简洁。然而,如果省略了 this,很难区分接收者成员和外部对象或函数之间的区别。因此,在主要通过调用其函数或为属性赋值来操作对象成员的 lambda 中,建议将上下文对象作为接收者 (this)。

val adam = Person("Adam").apply {  
  age = 20 // 与 this.age = 20 相同
  city = "London"
}
println(adam)
  • itlet 和 also 函数将上下文对象作为 lambda 参数引用。如果未指定参数名称,则可以使用隐式的默认名称 it 来访问对象。使用 it 比使用 this 更简洁,使用 it 的表达式通常更易读。然而,当调用对象的函数或属性时,不能像使用 this 那样隐式地访问对象。因此,当对象主要作为函数调用的参数时,通过 it 访问上下文对象更好。如果在代码块中使用多个变量,则使用 it 也更好。

fun getRandomInt(): Int {
  return Random.nextInt(100).also {
    writeToLog("getRandomInt() 生成的值为 $it")
  }
}

val i = getRandomInt()
println(i)

使用作用域函数的应用场景

作用域函数可以使代码更加清晰、易读和简洁,这是 Kotlin 语言的主要特点之一。

作用域函数的类型有五种:let、run、with、apply、also

这些函数之间的主要区别有两点:

  •  引用上下文对象的方式(使用 this 或 it 关键字)
  • 返回值(返回上下文对象或 lambda 结果)

作用域函数比较表:

函数 上下文对象引用 返回值
let it lambda 结果
run this lambda 结果
with this lambda 结果
apply this 对象本身
also it 对象本身

let 函数

  • 上下文对象:作为参数(it
  • 返回值:lambda 结果

使用场景let 函数经常用于处理可空对象以避免空指针异常。可以使用安全调用操作符(?.)结合 let 来进行空安全调用。它仅在非空值时执行代码块。

  • 可以用于在调用链中的结果上调用一个或多个函数。

示例

// 链式调用
val numbers = mutableListOf("one", "two", "three", "four", "five")
val resultList = numbers.map { it.length }.filter { it > 3 }
println(resultList)

// 使用 let
val numbers = mutableListOf("one", "two", "three", "four", "five")
numbers.map { it.length }
    .filter { it > 3 }
    .let { println(it) } // 可以继续添加更多函数调用
  • 空变量检查

val str: String? = "Hello"
// processNonNullString(str) // 编译错误:str 可能为空
val length = str?.let {
    println("let() 在 $it 上调用")
    processNonNullString(it) // OK:'it' 在 '?.let { }' 内部不为空
    it.length
}

with 函数

  • 上下文对象:作为接收者(this) 
  • 返回值:lambda 结果

使用场景:推荐使用 with 在上下文对象上调用函数,而不提供 lambda 结果。在代码中,我们可以将 with 理解为“对于这个对象,执行以下操作”。

示例

val numbers = mutableListOf("one", "two", "three")
with(numbers) {
    println("'with' 被调用,参数为 $this")
    println("它包含 $size 个元素")
}

run 函数

  •  上下文对象:作为接收者(this
  • 返回值:lambda 结果

使用场景run 在 lambda 中既可以初始化对象,又可以计算返回值。使用 run 我们可以进行空安全调用以及其他计算操作。

示例

   初始化和计算

val service = MultiportService("https://example.kotlinlang.org", 80)
val result = service.run {
    port = 8080
    query(prepareRequest() + " to port $port")
}
  • 链式空检查

val firstName: String? = null
var middleName: String? = null
var lastName: String? = null
middleName = "M "
lastName = "Vasava"
firstName?.run {
    val fullName = this + middleName + lastName
    print(fullName) // 仅打印 M Vasava
}

apply 函数

  • 上下文对象:作为接收者(this
  • 返回值:对象本身

使用场景:我们建议在不返回值的代码块中使用 apply,主要用于操作接收者对象的成员。最常见的用例是对象配置。我们可以理解这样的调用为“将以下赋值应用于该对象”。

示例

val adam = Person("Adam").apply {
    name = "Adam"
    age = 20
    city = "London"
}
println(adam)

also函数

  • 上下文对象:作为参数(it)。
  • 返回值:对象本身。

使用场景:可用于需要引用对象而不是其属性和函数的操作,或者当您不想从外部作用域隐藏 this 引用时。 当在代码中看到also时,可以将其读作“并且还对对象执行以下操作”。

来源:kotlin社区的文章

你可能感兴趣的:(kotlin,kotlin)