|  1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
 | class Test {
    data class Man(val name: String, val argOne: String = "456")
    private val argOne = "123"
    fun print() {
        Man("stefan").let {
            println(it.name)     //    it 代表 let 的调用方: Man
            println(this.argOne) //123 this 代表 print 方法的属主: class Test
            println(argOne)      //456 隐式调用 this 同上一行
            println(it.argOne)   //456
        }
        Man("stefanJ").run {
            println(this.name)   //    this 代表 run 的调用方: Man
            println(this.argOne) //456
            println(argOne)      //456 隐式调用 this,所以是 Man 中的 argOne
        }
         Man("stefanJi").apply {
            println(this.name)   //    this 代表 apply 的调用方: Man
            println(this.argOne) //456
            println(argOne)      //456 隐式调用 this
        }
        with(Man("stefanJiJ")) {
            println(this.name)   //   this 代表 with 接收的对象
            println(this.argOne) //456
            println(argOne)      //456
        }
    }
}
 | 
 
从上面的例子可以看出,let run apply 他们的本质区别是代码块里的能拿到的执行对象不一样:
- let是通过- it拿到当前执行对象
- run通过- this
- apply通过- this
但是 run 和 apply 貌似没有差别,既然名字不一样,肯定还是有差别的,看看他们的签名:
| 1
2
3
4
 | public inline fun <T, R> T.run(block: T.() -> R): R {
    //... 忽略中间部分
    return block()
}
 | 
 
run 的返回值是代码块的返回值
| 1
2
3
4
5
 | public inline fun <T> T.apply(block: T.() -> Unit): T {
    //... 忽略中间部分
    block()
    return this
}
 | 
 
apply 的返回值是当前对象
| 1
2
3
4
 | public inline fun <T, R> T.let(block: (T) -> R): R {
    //... 忽略中间部分
    return block(this)
}
 | 
 
let 的返回值也是代码块的返回值,且会把当前对象作为参数传入,这个参数默认名字叫 it,也可以自己取名字
| 1
2
3
4
5
6
 | Man("stefan").let { man ->
    println(man.name)    //    man 代表 let 的调用方: Man
    println(this.argOne) //123 this 代表 print 方法的属主: class Test
    println(argOne)      //456 隐式调用 this 同上一行
    println(man.argOne)  //456
}
 | 
 
| 1
2
3
4
 | public inline fun <T, R> with(receiver: T, block: T.() -> R): R {
    //... 忽略中间部分
    return receiver.block()
}
 | 
 
而且 let run apply 都是 T.xx 的方式定义,说明他们是作为任意对象的一个扩展函数使用,而with则是作为普通的顶层函数使用。