kotlin function: run with let also apply

Scoping functions (作用域 函数)

提供了一个 内部独立的区间(也就是方法的上下文 如下的run方法)

  • run{} 提供独立上下文
  • with(T){} 上下文为参数
  • T.run{} 对比with(T) T.run{}是个拓展方法 extension function,默认参数是T. 就是T相当于方法内部(作用域内)的this
  • T.let{} 默认参数是T 就是T相当于lambda的参数
  • T.also{} return值在链式调用中一直为T
  • T.apply{}
run
fun test() {
    var mood = "I am sad"

    run {
        val mood = "I am happy"
        println(mood) // I am happy
    }

    println(mood)  // I am sad
}
  • Scope
    如上 run内部是一个区间mode,外部是另一个区间。所以mode使用的是run内部的
  • return value
    run {
        if (firstTimeView) introView else normalView
    }.show()
scope function 3个属性

从这三个属性的维度 来对上述方法,再次划分
1. Normal vs. extension function

//normal function
with(webview.settings) {
    javaScriptEnabled = true
    databaseEnabled = true
}
// similarly function
// extension function
webview.settings.run {
    javaScriptEnabled = true
    databaseEnabled = true
}

好处 webview.settings 可能为null,所以安全的写法:

// Yack!
with(webview.settings) {
      this?.javaScriptEnabled = true
      this?.databaseEnabled = true
   }
}
// Nice.
webview.settings?.run {
    javaScriptEnabled = true
    databaseEnabled = true
}
  1. This vs. it argument

T.run和T.let只有一点不同 他们接受的参数

stringVariable?.run {
      println("The length of this String is $length")
}
// Similarly.
stringVariable?.let {
      println("The length of this String is ${it.length}")
}

看方法的signature(方法签名,包括方法参数列表),发现T.run是一个扩展方法block: T.() 所以在scope内T是被当做this,方法中this可以被省略,所以$length 等价于${this.length}

T.let方法的signature是block: (T) 像lambda表达式一样,这里我们成为 it 参数

另外it也是可以改名的:

stringVariable?.let {
      nonNullString ->
      println("The non null string is $nonNullString")
}
  1. Return this vs. other type

T.let and T.also

val original = "abc"

// Evolve the value and send to the next chain
original.let {
    println("The original String is $it") // "abc"
    it.reversed() // evolve it as parameter to send to next let
}.let {
    println("The reverse String is $it") // "cba"
    it.length  // can be evolve to other type
}.let {
    println("The length of the String is $it") // 3
}

// Wrong
// Same value is sent in the chain (printed answer is wrong)
original.also {
    println("The original String is $it") // "abc"
    it.reversed() // even if we evolve it, it is useless
}.also {
    println("The reverse String is ${it}") // "abc"
    it.length  // even if we evolve it, it is useless
}.also {
    println("The length of the String is ${it}") // "abc"
}

// Corrected for also (i.e. manipulate as original string
// Same value is sent in the chain 
original.also {
    println("The original String is $it") // "abc"
}.also {
    println("The reverse String is ${it.reversed()}") // "cba"
}.also {
    println("The length of the String is ${it.length}") // 3
}

let return的是这次调用的结果,also return的仍旧是调用方

also看起来没用,可以整合到一个方法,但是也有好处:
1. It can provide a very clear separation process on the same objects i.e. making smaller functional section. (更细粒度的分割代码、逻辑)
2. It can be very powerful for self manipulation before being used, making a chaining builder operation.(有利于build模式)

结合使用
// Normal approach
fun makeDir(path: String): File  {
    val result = File(path)
    result.mkdirs()
    return result
}
// Improved approach
fun makeDir(path: String) = path.let{ File(it) }.also{ it.mkdirs() }

另外T.apply

  1. It is an extension function
  2. It send this as it’s argument.
  3. It returns this (i.e. itself)

上面说的this实际就是T

// Normal approach
fun createInstance(args: Bundle) : MyFragment {
    val fragment = MyFragment()
    fragment.arguments = args
    return fragment
}
// Improved approach
fun createInstance(args: Bundle) 
              = MyFragment().apply { arguments = args }

非链式的做成链式调用

// Normal approach
fun createIntent(intentData: String, intentAction: String): Intent {
    val intent = Intent()
    intent.action = intentAction
    intent.data=Uri.parse(intentData)
    return intent
}
// Improved approach, chaining
fun createIntent(intentData: String, intentAction: String) =
        Intent().apply { action = intentAction }
                .apply { data = Uri.parse(intentData) }

方法的选择

原文: Mastering Kotlin standard functions: run, with, let, also and apply

你可能感兴趣的:(Android,Kotlin)