Kotlin 函数进阶 作用域函数:let、with、also...

Kotlin—— 作用域函数

    • 概述
      • 官方文档
      • 简介
      • 作用
      • 五个函数
      • ★区别
    • 区别详解
      • 引用方法: this 还是 it
        • 使用this的函数
        • 使用it的函数
      • 返回值
        • 返回上下文对象(本身)
        • 返回Lambda表达式结果( 返回一个结果 默认为最后一行代码 可以为空)
    • 五个函数详解
      • let (使用it 、返回lambda对象)
      • with (使用this,返回lambda结果)
      • run (使用this,返回lambda结果)
      • apply(使用this,返回值为本身)
      • also(使用it,返回值为本身 )
      • 各函数差异以及使用场景

概述

官方文档

地址

简介

官方解释:

The Kotlin standard library contains several functions whose sole purpose is to execute a block of code within the context of an object. When you call such a function on an object with a lambda expression provided, it forms a temporary scope. In this scope, you can access the object without its name. Such functions are called scope functions
Basically, these functions do the same: execute a block of code on an object. What’s different is how this object becomes available inside the block and what is the result of the whole expression.

大概意思就是kotlin提供这样的语法糖:我们可以在某个对象的“上下文环境”中,创建一个临时的作用域,在这个区域我们可以不显示的调用对象(用it 或者 this),并且当中的变量也是区域性的,共有五个这样的函数,功能相似

作用

那为什么要用呢?很简单,就是增加可读性,更加简洁

五个函数

  • let
  • run
  • with
  • apply
  • also

★区别

  • 引用上下文对象的方法(使用it还是this)
  • 返回值(返回对象本身,还是一个lambda表达式结果)

区别详解

先看两个区别:

引用方法: this 还是 it

使用this的函数

run、with、apply 使用的context是 this,和其他地方一样,这里的this是可以省略的,但是容易弄混。并且引用的对象是“可见的”,官方参考:

val adam = Person("Adam").apply { 
    age = 20         // same as this.age = 20 or adam.age = 20
    city = "London"
}

print(adam.age)   // output 20

使用it的函数

与之对应的,剩下的 let、also,将上下文对象作为lambda(即作用域代码块)的参数,如果未指定参数名,则默认名称访问该对象,当然也可以为 上下文对象 自定义名称
(上下文对象就是使用这个方法的对象)

fun getRandomInt(): Int {
    return Random.nextInt(100).also {
        writeToLog("getRandomInt() generated value $it")
       // print("getRandomInt() generated value $it")
    }
}

val i = getRandomInt()

// 自定义名称的情况

fun getRandomInt(): Int {
    return Random.nextInt(100).also { value ->
            writeToLog("getRandomInt() generated value $value")
    }
}

返回值

返回上下文对象(本身)

apply 和 also 返回值是上下文对象本身,也就是说可以对同一个对象进行链式调用

val numberList = mutableListOf<Double>()
numberList.also { println("Populating the list") }
    .apply {
        add(2.71)
        add(3.14)
        add(1.0)
    }
    .also { println("Sorting the list") }
    .sort()
    
// output

Populating the list 
Sorting the list 
[1.0, 2.71, 3.14]

返回Lambda表达式结果( 返回一个结果 默认为最后一行代码 可以为空)

let, run,和with返回一个lambda结果

// 官方实例
val numbers = mutableListOf("one", "two", "three")
val countEndsWithE = numbers.run { 
    add("four")
    add("five")
    count { it.endsWith("e") }
}
println("There are $countEndsWithE elements that end with e.")

// output
There are 3 elements that end with e.

// 稍微修改下:

val numbers = mutableListOf("one", "two", "three")
val countEndsWithE = numbers.run {  
    add("four") 
    add("five") 
    this.count { it.endsWith("e") }
    println("123") // 忽略了返回值 返回有空
    // 5     如果最后一行是 ‘5’ 则countEndsWithE 值为5,输出为5
}
println(countEndsWithE)
// output
123
kotlin.Unit

五个函数详解

let (使用it 、返回lambda对象)

通常用于执行非空,我们可以用他代替if(object != null ){ … },官方例子

// 不用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)
    map.filter{ it > 4}
    // and more function calls if needed
} 

另一例使用let是在有限的范围内引入局部变量,以提高代码的可读性。若要为上下文对象定义一个新变量,请将其名称作为lambda参数,以便可以使用它而不是默认的it.

fun main() {
    val numbers = listOf("one", "two", "three", "four")
    val modifiedFirstItem = numbers.first().let { firstItem ->
            println("The first item of the list is '$firstItem'")
        if (firstItem.length >= 5) firstItem else "!" + firstItem + "!"
    }.toUpperCase()
    println("First item after modifications: '$modifiedFirstItem'")
}
// output
The first item of the list is 'one'
First item after modifications: '!ONE!'

with (使用this,返回lambda结果)

非扩展函数(A non-extension function),“上下文对象”作为参数传递,可以用“this”,“返回值是lambda的结果”(最后一行的结果),但是官方建议是在“不提供lambda结果的情况下调用上下文对象上的函数”,可以理解为,使用此对象,执行以下操作

val numbers = mutableListOf("one", "two", "three")
with(numbers) {
    println("'with' is called with argument $this")
    println("It contains $size elements")
}

// output
'with' is called with argument [one, two, three]
It contains 3 elements

也可以用于计算一些值:

fun main() {
    val numbers = mutableListOf("one", "two", "three")
    val firstAndLast = with(numbers) {
        "The first element is ${first()}," +
            " the last element is ${last()}"
    }
    println(firstAndLast)
}

run (使用this,返回lambda结果)

上下文对象可作为接收者(this). 返回值是lambda结果
和with差不多,常用于:同时包含对象初始化和返回值的计算

val service = MultiportService("https://example.kotlinlang.org", 80)

val result = service.run {
    port = 8080
    query(prepareRequest() + " to port $port")
}

// the same code written with let() function:
val letResult = service.let {
    it.port = 8080
    it.query(it.prepareRequest() + " to port ${it.port}")
}

apply(使用this,返回值为本身)

上下文对象为this,返回值为本身,主要用于不返回值,并且对自身进行一些配置的情况下

    val adam = Person("Adam").apply {
        age = 32
        city = "London"        
    }

also(使用it,返回值为本身 )

上下文对象为it ,返回值为本身,使用场景:有关不更改对象的其他操作,如日志记录或打印调试信息

val numbers = mutableListOf("one", "two", "three")
numbers
    .also { println("The list elements before adding new one: $it") }
    .add("four")
    
// output
The list elements before adding new one: [one, two, three]

各函数差异以及使用场景

名称 对象引用 返回值 是否为拓展函数 使用场景
let it Lambda结果 对非空对象执行(替代 !=)
run this Lambda结果 对象的配置、计算结果
run - Lambda结果 否:在没有上下文对象的情况下调用 运行需要表达式的语句
with this Lambda结果 否:接受上下文对象作为参数 同一个对象调用多个方法
apply this 上下文对象 用于对象的配置
also it 上下文对象 用于一些附加操作

你可能感兴趣的:(Kotlin学习之路)