<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??碼云GVP開源項目 12k star Uniapp+ElementUI 功能強大 支持多語言、二開方便! 廣告
                # 作用域函數 Kotlin 標準庫包含幾個函數,它們的唯一目的是在對象的上下文中執行代碼塊。當對一個對象調用這樣的函數并提供一個 [lambda 表達式](http://www.kotlincn.net/docs/reference/lambdas.html)時,它會形成一個臨時作用域。在此作用域中,可以訪問該對象而無需其名稱。這些函數稱為*作用域函數*。共有以下五種:`let`、`run`、`with`、`apply` 以及 `also`。 這些函數基本上做了同樣的事情:在一個對象上執行一個代碼塊。不同的是這個對象在塊中如何使用,以及整個表達式的結果是什么。 下面是作用域函數的典型用法: ```kotlin data class Person(var name: String, var age: Int, var city: String) { fun moveTo(newCity: String) { city = newCity } fun incrementAge() { age++ } } fun main() { Person("Alice", 20, "Amsterdam").let { println(it) it.moveTo("London") it.incrementAge() println(it) } } ``` 如果不使用 `let` 來寫這段代碼, 就必須引入一個新變量,并在每次使用它時重復其名稱。 ```kotlin data class Person(var name: String, var age: Int, var city: String) { fun moveTo(newCity: String) { city = newCity } fun incrementAge() { age++ } } fun main() { val alice = Person("Alice", 20, "Amsterdam") println(alice) alice.moveTo("London") alice.incrementAge() println(alice) } ``` 作用域函數沒有引入任何新的技術,但是它們可以使你的代碼更加簡潔易讀。 由于作用域函數的相似性質,為你的案例選擇正確的函數可能有點棘手。選擇主要取決于你的意圖和項目中使用的一致性。下面我們將詳細描述各種作用域函數及其約定用法之間的區別。 ## 區別 由于作用域函數本質上都非常相似,因此了解它們之間的區別很重要。每個作用域函數之間有兩個主要區別: * 引用上下文對象的方式 * 返回值 ### 上下文對象:`this` 還是 `it` 在作用域函數的 lambda 表達式里,上下文對象可以不使用其實際名稱而是使用一個更簡短的引用來訪問。每個作用域函數都使用以下兩種方式之一來訪問上下文對象:作為 lambda 的[接收者](lambdas.html#帶有接收者的函數字面值)(`this`)或者作為 lambda 的參數(`it`)。兩者都提供了同樣的功能,因此我們將針對不同的場景描述兩者的優缺點,并提供使用建議。 ```kotlin fun main() { val str = "Hello" // this str.run { println("The receiver string length: $length") //println("The receiver string length: ${this.length}") // 和上句效果相同 } // it str.let { println("The receiver string's length is ${it.length}") } } ``` #### this `run`、`with` 以及 `apply` 通過關鍵字 `this` 引用上下文對象。因此,在它們的 lambda 表達式中可以像在普通的類函數中一樣訪問上下文對象。在大多數場景,當你訪問接收者對象時你可以省略 `this`,來讓你的代碼更簡短。相對地,如果省略了 `this`,就很難區分接收者對象的成員及外部對象或函數。因此,對于主要對對象成員進行操作(調用其函數或賦值其屬性)的 lambda,建議將上下文對象作為接收者(`this`)。 ```kotlin data class Person(var name: String, var age: Int = 0, var city: String = "") fun main() { val adam = Person("Adam").apply { age = 20 // 和 this.age = 20 或者 adam.age = 20 一樣 city = "London" } } ``` #### it 反過來,`let` 及 `also` 將上下文對象作為 lambda 表達式參數。如果沒有指定參數名,對象可以用隱式默認名稱 `it` 訪問。`it` 比 `this` 簡短,帶有 `it` 的表達式通常更容易閱讀。然而,當調用對象函數或屬性時,不能像 `this` 這樣隱式地訪問對象。因此,當上下文對象在作用域中主要用作函數調用中的參數時,使用 `it` 作為上下文對象會更好。若在代碼塊中使用多個變量,則 `it` 也更好。 ```kotlin import kotlin.random.Random fun writeToLog(message: String) { println("INFO: $message") } fun main() { fun getRandomInt(): Int { return Random.nextInt(100).also { writeToLog("getRandomInt() generated value $it") } } val i = getRandomInt() } ``` 此外,當將上下文對象作為參數傳遞時,可以為上下文對象指定在作用域內的自定義名稱。 ```kotlin import kotlin.random.Random fun writeToLog(message: String) { println("INFO: $message") } fun main() { fun getRandomInt(): Int { return Random.nextInt(100).also { value -> writeToLog("getRandomInt() generated value $value") } } val i = getRandomInt() } ``` ### 返回值 根據返回結果,作用域函數可以分為以下兩類: * `apply` 及 `also` 返回上下文對象。 * `let`、`run` 及 `with` 返回 lambda 表達式結果. 這兩個選項使你可以根據在代碼中的后續操作來選擇適當的函數。 #### 上下文對象 `apply` 及 `also` 的返回值是上下文對象本身。因此,它們可以作為輔助步驟包含在調用鏈中:你可以繼續在同一個對象上進行鏈式函數調用。 ```kotlin fun main() { 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() println(numberList) } ``` 它們還可以用在返回上下文對象的函數的 return 語句中。 ```kotlin import kotlin.random.Random fun writeToLog(message: String) { println("INFO: $message") } fun main() { fun getRandomInt(): Int { return Random.nextInt(100).also { writeToLog("getRandomInt() generated value $it") } } val i = getRandomInt() } ``` #### Lambda 表達式結果 `let`、`run` 及 `with` 返回 lambda 表達式的結果。所以,在需要使用其結果給一個變量賦值,或者在需要對其結果進行鏈式操作等情況下,可以使用它們。 ```kotlin fun main() { 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.") } ``` 此外,還可以忽略返回值,僅使用作用域函數為變量創建一個臨時作用域。 ```kotlin fun main() { val numbers = mutableListOf("one", "two", "three") with(numbers) { val firstItem = first() val lastItem = last() println("First item: $firstItem, last item: $lastItem") } } ``` ## 幾個函數 To help you choose the right scope function for your case, we'll describe them in detail and provide usage recommendations. Technically, functions are interchangeable in many cases, so the examples show the conventions that define the common usage style. ### `let` **The context object** is available as an argument (`it`). **The return value** is the lambda result. `let` can be used to invoke one or more functions on results of call chains. For example, the following code prints the results of two operations on a collection: ```kotlin fun main() { val numbers = mutableListOf("one", "two", "three", "four", "five") val resultList = numbers.map { it.length }.filter { it > 3 } println(resultList) } ``` With `let`, you can rewrite it: ```kotlin fun main() { val numbers = mutableListOf("one", "two", "three", "four", "five") numbers.map { it.length }.filter { it > 3 }.let { println(it) // and more function calls if needed } } ``` If the code block contains a single function with `it` as an argument, you can use the method reference (`::`) instead of the lambda: ```kotlin fun main() { val numbers = mutableListOf("one", "two", "three", "four", "five") numbers.map { it.length }.filter { it > 3 }.let(::println) } ``` `let` is often used for executing a code block only with non-null values. To perform actions on a non-null object, use the safe call operator `?.` on it and call `let` with the actions in its lambda. ```kotlin fun processNonNullString(str: String) {} fun main() { val str: String? = "Hello" //processNonNullString(str) // compilation error: str can be null val length = str?.let { println("let() called on $it") processNonNullString(it) // OK: 'it' is not null inside '?.let { }' it.length } } ``` Another case for using `let` is introducing local variables with a limited scope for improving code readability. To define a new variable for the context object, provide its name as the lambda argument so that it can be used instead of the default `it`. ```kotlin 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'") } ``` ### `with` A non-extension function: **the context object** is passed as an argument, but inside the lambda, it's available as a receiver (`this`). **The return value** is the lambda result. We recommend `with` for calling functions on the context object without providing the lambda result. In the code, `with` can be read as “_with this object, do the following._” ```kotlin fun main() { val numbers = mutableListOf("one", "two", "three") with(numbers) { println("'with' is called with argument $this") println("It contains $size elements") } } ``` Another use case for `with` is introducing a helper object whose properties or functions will be used for calculating a value. ```kotlin 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` **The context object** is available as a receiver (`this`). **The return value** is the lambda result. `run` does the same as `with` but invokes as `let` - as an extension function of the context object. `run` is useful when your lambda contains both the object initialization and the computation of the return value. ```kotlin class MultiportService(var url: String, var port: Int) { fun prepareRequest(): String = "Default request" fun query(request: String): String = "Result for query '$request'" } fun main() { 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}") } println(result) println(letResult) } ``` Besides calling `run` on a receiver object, you can use it as a non-extension function. Non-extension `run` lets you execute a block of several statements where an expression is required. ```kotlin fun main() { val hexNumberRegex = run { val digits = "0-9" val hexDigits = "A-Fa-f" val sign = "+-" Regex("[$sign]?[$digits$hexDigits]+") } for (match in hexNumberRegex.findAll("+1234 -FFFF not-a-number")) { println(match.value) } } ``` ### `apply` **The context object** is available as a receiver (`this`). **The return value** is the object itself. Use `apply` for code blocks that don't return a value and mainly operate on the members of the receiver object. The common case for `apply` is the object configuration. Such calls can be read as “_apply the following assignments to the object._” ```kotlin data class Person(var name: String, var age: Int = 0, var city: String = "") fun main() { val adam = Person("Adam").apply { age = 32 city = "London" } } ``` Having the receiver as the return value, you can easily include `apply` into call chains for more complex processing. ### `also` **The context object** is available as an argument (`it`). **The return value** is the object itself. `also` is good for performing some actions that take the context object as an argument. Use `also` for additional actions that don't alter the object, such as logging or printing debug information. Usually, you can remove the calls of `also` from the call chain without breaking the program logic. When you see `also` in the code, you can read it as “_and also do the following_”. ```kotlin fun main() { val numbers = mutableListOf("one", "two", "three") numbers .also { println("The list elements before adding new one: $it") } .add("four") } ``` ## 函數選擇 To help you choose the right scope function for your purpose, we provide the table of key differences between them. |Function|Object reference|Return value|Is extension function| |---|---|---|---| |`let`|`it`|Lambda result|Yes| |`run`|`this`|Lambda result|Yes| |`run`|-|Lambda result|No: called without the context object| |`with`|`this`|Lambda result|No: takes the context object as an argument.| |`apply`|`this`|Context object|Yes| |`also`|`it`|Context object|Yes| Here is a short guide for choosing scope functions depending on the intended purpose: * Executing a lambda on non-null objects: `let` * Introducing an expression as a variable in local scope: `let` * Object configuration: `apply` * Object configuration and computing the result: `run` * Running statements where an expression is required: non-extension `run` * Additional effects: `also` * Grouping function calls on an object: `with` The use cases of different functions overlap, so that you can choose the functions based on the specific conventions used in your project or team. Although the scope functions are a way of making the code more concise, avoid overusing them: it can decrease your code readability and lead to errors. Avoid nesting scope functions and be careful when chaining them: it's easy to get confused about the current context object and the value of `this` or `it`. ## `takeIf` 與 `takeUnless` In addition to scope functions, the standard library contains the functions `takeIf` and `takeUnless`. These functions let you embed checks of the object state in call chains. When called on an object with a predicate provided, `takeIf` returns this object if it matches the predicate. Otherwise, it returns `null`. So, `takeIf` is a filtering function for a single object. In turn, `takeUnless` returns the object if it doesn't match the predicate and `null` if it does. The object is available as a lambda argument (`it`). ```kotlin import kotlin.random.* fun main() { val number = Random.nextInt(100) val evenOrNull = number.takeIf { it % 2 == 0 } val oddOrNull = number.takeUnless { it % 2 == 0 } println("even: $evenOrNull, odd: $oddOrNull") } ``` When chaining other functions after `takeIf` and `takeUnless`, don't forget to perform the null check or the safe call (`?.`) because their return value is nullable. ```kotlin fun main() { val str = "Hello" val caps = str.takeIf { it.isNotEmpty() }?.toUpperCase() //val caps = str.takeIf { it.isNotEmpty() }.toUpperCase() //compilation error println(caps) } ``` `takeIf` and `takeUnless` are especially useful together with scope functions. A good case is chaining them with `let` for running a code block on objects that match the given predicate. To do this, call `takeIf` on the object and then call `let` with a safe call (`?`). For objects that don't match the predicate, `takeIf` returns `null` and `let` isn't invoked. ```kotlin fun main() { fun displaySubstringPosition(input: String, sub: String) { input.indexOf(sub).takeIf { it >= 0 }?.let { println("The substring $sub is found in $input.") println("Its start position is $it.") } } displaySubstringPosition("010000011", "11") displaySubstringPosition("010000011", "12") } ``` This is how the same function looks without the standard library functions: ```kotlin fun main() { fun displaySubstringPosition(input: String, sub: String) { val index = input.indexOf(sub) if (index >= 0) { println("The substring $sub is found in $input.") println("Its start position is $index.") } } displaySubstringPosition("010000011", "11") displaySubstringPosition("010000011", "12") } ```
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看