Kotlin 學習之函數(shù)與 Lambda 表達式

函數(shù)

函數(shù)聲明

Kotlin 中的函數(shù)使用 fun 關(guān)鍵字聲明,其code表現(xiàn)形式:

fun double(x: Int): Int {
return 2 * x
}

函數(shù)用法

調(diào)用函數(shù)使用傳統(tǒng)的方法:

val result = double(2)

調(diào)用成員函數(shù)使用點表示法

Stream().read() // 創(chuàng)建類 Stream 實例并調(diào)用 read()
val funDemo = FunDemo()
val result = funDemo.double(2)

參數(shù)

函數(shù)參數(shù)使用 Pascal 表示法定義,即 name: type昆咽。參數(shù)用逗號隔開。每個參數(shù)必須有顯式類型:

fun powerOf(number: Int, exponent: Int) { /*......*/ }

默認參數(shù)

函數(shù)參數(shù)可以有默認值,當省略相應的參數(shù)時使用默認值腹暖。與其他語言相比,這可以減少重載數(shù)量:

fun read(b: Array<Byte>, off: Int = 0, len: Int = b.size) { /*......*/ }

默認值通過類型后面的 = 及給出的值來定義。
覆蓋方法總是使用與基類型方法相同的默認參數(shù)值亩鬼。 當覆蓋一個帶有默認參數(shù)值的方法時,必須從簽名
中省略默認參數(shù)值:

open class A {
open fun foo(i: Int = 10) { /*......*/ }
}
class B : A() {
override fun foo(i: Int) { /*......*/ }
}

如果一個默認參數(shù)在一個無默認值的參數(shù)之前,那么該默認值只能通過使用具名參數(shù)調(diào)用該函數(shù)來使
用:

fun foo(bar: Int = 0, baz: Int) { /*......*/ }
foo(baz = 1) // 使用默認值 bar = 0

如果在默認參數(shù)之后的最后一個參數(shù)是 lambda 表達式,那么它既可以作為具名參數(shù)在括號內(nèi)傳入,也
可以在括號外傳入:

fun foo(bar: Int = 0, baz: Int = 1, qux: () -> Unit) { /*......*/ }
foo(1) { println("hello") }
// 使用默認值 baz = 1
foo(qux = { println("hello") }) // 使用兩個默認值 bar = 0 與 baz = 1
foo { println("hello") }  // 使用兩個默認值 bar = 0 與 baz = 1

具名參數(shù)

可以在調(diào)用函數(shù)時使用具名的函數(shù)參數(shù)。當一個函數(shù)有大量的參數(shù)或默認參數(shù)時這會非常方便爽丹。
給定以下函數(shù):

fun reformat(str: String,
normalizeCase: Boolean = true,
upperCaseFirstLetter: Boolean = true,
divideByCamelHumps: Boolean = false,
wordSeparator: Char = ' ') {
/*......*/
}

我們可以使用默認參數(shù)來調(diào)用它:

reformat(str)

然而,當使用非默認參數(shù)調(diào)用它時,該調(diào)用看起來就像:

reformat(str, true, true, false, '_')

使用具名參數(shù)我們可以使代碼更具有可讀性:

reformat(str,
normalizeCase = true,
upperCaseFirstLetter = true,
divideByCamelHumps = false,
wordSeparator = '_'
)

并且如果我們不需要所有的參數(shù):

reformat(str, wordSeparator = '_')

當一個函數(shù)調(diào)用混用位置參數(shù)與具名參數(shù)時,所有位置參數(shù)都要放在第一個具名參數(shù)之前粤蝎。
例如,允許調(diào)用 f(1, y = 2) 但不允許 f(x = 1, 2) 。
當一個函數(shù)調(diào)用混用位置參數(shù)與具名參數(shù)時,所有位置參數(shù)都要放在第一個具名參數(shù)之前碑宴。
例如,允許
調(diào)用 f(1, y = 2) 但不允許 f(x = 1, 2) 延柠。
可以通過使用星號操作符將可變數(shù)量參數(shù)(vararg) 以具名形式傳入:

fun foo(vararg strings: String) { /*......*/ }
foo(strings = *arrayOf("a", "b", "c"))
//對于 JVM 平臺:在調(diào)用 Java 函數(shù)時不能使用具名參數(shù)語法,因為 Java 字節(jié)碼并不總是保留函數(shù)
參數(shù)的名稱捕仔。

返回 Unit 的函數(shù)

如果一個函數(shù)不返回任何有用的值,它的返回類型是 Unit 。 Unit 是一種只有一個值? Unit 的類
型钓葫。這個值不需要顯式返回:

fun printHello(name: String?): Unit {
if (name != null)
println("Hello ${name}")
else
println("Hi there!")
// `return Unit` 或者 `return` 是可選的
}

Unit 返回類型聲明也是可選的票顾。
上面的代碼等同于:

fun printHello(name: String?) { ...... }

單表達式函數(shù)

當函數(shù)返回單個表達式時,可以省略花括號并且在 = 符號之后指定代碼體即可:

fun double(x: Int): Int = x * 2

當返回值類型可由編譯器推斷時,顯式聲明返回類型是可選的:

fun double(x: Int) = x * 2

顯式返回類型

具有塊代碼體的函數(shù)必須始終顯式指定返回類型,除非他們旨在返回 Unit ,在這種情況下它是可選
的。 Kotlin 不推斷具有塊代碼體的函數(shù)的返回類型,因為這樣的函數(shù)在代碼體中可能有復雜的控制流,
并且返回類型對于讀者(有時甚至對于編譯器)是不明顯的。

可變數(shù)量的參數(shù)(Varargs)

函數(shù)的參數(shù)(通常是最后一個)可以用 vararg 修飾符標記:

fun <T> asList(vararg ts: T): List<T> {
val result = ArrayList<T>()
for (t in ts) // ts is an Array
result.add(t)
return result
}

允許將可變數(shù)量的參數(shù)傳遞給函數(shù):

val list = asList(1, 2, 3)

在函數(shù)內(nèi)部,類型 T 的 vararg 參數(shù)的可?方式是作為 T 數(shù)組,即上例中的 ts 變量具有類型
Array <out T> 芹务。
只有一個參數(shù)可以標注為 vararg 。
如果 vararg 參數(shù)不是列表中的最后一個參數(shù), 可以使用具名參
數(shù)語法傳遞其后的參數(shù)的值,或者,如果參數(shù)具有函數(shù)類型,則通過在括號外部傳一個 lambda佳晶。
當我們調(diào)用 vararg -函數(shù)時,我們可以一個接一個地傳參,例如 asList(1, 2, 3) ,或者,如果我們
已經(jīng)有一個數(shù)組并希望將其內(nèi)容傳給該函數(shù),我們使用伸展(spread) 操作符(在數(shù)組前面加 * ):

val a = arrayOf(1, 2, 3)
val list = asList(-1, 0, *a, 4)

中綴表示法

標有 infix 關(guān)鍵字的函數(shù)也可以使用中綴表示法(忽略該調(diào)用的點與圓括號)調(diào)用轿秧。
中綴函數(shù)必須滿足
以下要求:

  • 它們必須是成員函數(shù)或擴展函數(shù);
  • 它們必須只有一個參數(shù);
  • 其參數(shù)不得接受可變數(shù)量的參數(shù)且不能有默認值。
infix fun Int.shl(x: Int): Int { ...... }
// 用中綴表示法調(diào)用該函數(shù)
1 shl 2
// 等同于這樣
1.shl(2)

中綴函數(shù)調(diào)用的優(yōu)先級低于算術(shù)操作符陨仅、類型轉(zhuǎn)換以及 rangeTo 操作符灼伤。 以下表達式是等價
的:
— 1 shl 2 + 3 等價于 1 shl (2 + 3)
— 0 until n * 2 等價于 0 until (n * 2)
— xs union ys as Set<> 等價于 xs union (ys as Set<>)
另一方面,中綴函數(shù)調(diào)用的優(yōu)先級高于布爾操作符 && 與 ||撞鹉、 is- 與 in- 檢測以及其他一些操
作符鸟雏。
這些表達式也是等價的:
— a && b xor c 等價于 a && (b xor c)
— a xor b in c 等價于 (a xor b) in c

請注意,中綴函數(shù)總是要求指定接收者與參數(shù)览祖。
當使用中綴表示法在當前接收者上調(diào)用方法時,需要顯
式使用 this ;不能像常規(guī)方法調(diào)用那樣省略孝鹊。
這是確保非模糊解析所必需的。

    //infix  美 [in`fiks. `in-. `infiks] 
    //vt. 把…印入展蒂;把…插進
    //n. 中綴又活;插入詞
    class MyStringCollection {
        infix fun add(s: String) { /*......*/ }
        fun build() {
            this add "abc"  // 正確
            add("abc")      // 正確
            //add "abc"     // 錯誤:必須指定接收者
        }
    }

函數(shù)作用域

在 Kotlin 中函數(shù)可以在文件頂層聲明,這意味著你不需要像一些語言如 Java苔咪、C# 或 Scala 那樣需要創(chuàng)
建一個類來保存一個函數(shù)。
此外除了頂層函數(shù),Kotlin 中函數(shù)也可以聲明在局部作用域柳骄、作為成員函數(shù)
以及擴展函數(shù)团赏。

局部函數(shù)

Kotlin 支持局部函數(shù),即一個函數(shù)在另一個函數(shù)內(nèi)部:

    fun dfs(graph: Graph) {
        fun dfs(current: Vertex, visited: MutableSet<Vertex>) {
            if (!visited.add(current)) return
            for (v in current.neighbors)
                dfs(v, visited)
        }
        dfs(graph.vertices[0], HashSet())
    }

局部函數(shù)可以訪問外部函數(shù)(即閉包)的局部變量,所以在上例中,visited 可以是局部變量:

    fun dfs1(graph: Graph) {
        val visited = HashSet<Vertex>()
        fun dfs(current: Vertex) {
            if (!visited.add(current)) return
            for (v in current.neighbors)
                dfs(v)
        }
        dfs(graph.vertices[0])
    }

成員函數(shù)

成員函數(shù)是在類或?qū)ο髢?nèi)部定義的函數(shù):

class Sample() {
    fun foo() { print("Foo") }
}

成員函數(shù)以點表示法調(diào)用:

Sample().foo() // 創(chuàng)建類 Sample 實例并調(diào)用 foo

高階函數(shù)與 lambda 表達式

Kotlin 函數(shù)都是 頭等的,這意味著它們可以存儲在變量與數(shù)據(jù)結(jié)構(gòu)中、作為參數(shù)傳遞給其他高階函數(shù)以
及從其他高階函數(shù)返回。可以像操作任何其他非函數(shù)值一樣操作函數(shù)。
為促成這點,作為一?靜態(tài)類型編程語言的 Kotlin 使用一系列函數(shù)類型來表示函數(shù)并提供一組特定的
語言結(jié)構(gòu),例如 lambda 表達式。

高階函數(shù)

高階函數(shù)是將函數(shù)用作參數(shù)或返回值的函數(shù)。
一個不錯的示例是集合的函數(shù)式?格的 fold, 它接受一個初始累積值與一個接合函數(shù),并通過將當前
累積值與每個集合元素連續(xù)接合起來代入累積值來構(gòu)建返回值:

   /*
      combine
     美 [kEm`bain] vt. 使化合丰捷;使聯(lián)合停巷,使結(jié)合 vi. 聯(lián)合硼被,結(jié)合;化合 n. 聯(lián)合收割機;聯(lián)合企業(yè)
     accumulator
     accumulator [??kju?mj?le?t?(r)]  n. 蓄電池;[計] 累加器五嫂;積聚者
     */
    fun <T, R> Collection<T>.fold(
        initial: R,
        combine: (acc: R, nextElement: T) -> R
    ): R {
        var accumulator: R = initial
        for (element: T in this) {
            accumulator = combine(accumulator, element)
        }
        return accumulator
    }

在上述代碼中,參數(shù) combine 具有函數(shù)類型 (R, T) -> R ,因此 fold 接受一個函數(shù)作為參數(shù), 該
函數(shù)接受類型分別為 R 與 T 的兩個參數(shù)并返回一個 R 類型的值。 在 for-循環(huán)內(nèi)部調(diào)用該函數(shù),然后
將其返回值賦值給 accumulator 。
為了調(diào)用 fold ,需要傳給它一個函數(shù)類型的實例作為參數(shù),而在高階函數(shù)調(diào)用處, (下文詳述的)lambda 表達 式廣泛用于此目的。

   fun testFold() {
       val items = listOf(1, 2, 3, 4, 5)
       // Lambdas 表達式是花括號括起來的代碼塊槽棍。
       items.fold(0, {
       // 如果一個 lambda 表達式有參數(shù),前面是參數(shù),后跟“->”
               acc: Int, i: Int ->
           print("acc = $acc, i = $i, ")
           val result = acc + i
           println("result = $result")
       // lambda 表達式中的最后一個表達式是返回值:
           result
       })
       // lambda 表達式的參數(shù)類型是可選的,如果能夠推斷出來的話:
       val joinedToString = items.fold("Elements:", { acc, i -> acc + " " + i })
        // 函數(shù)引用也可以用于高階函數(shù)調(diào)用:
       val product = items.fold(1, Int::times)
   }

以下各節(jié)會更詳細地解釋上文提到的這些概念。

函數(shù)類型

Kotlin 使用類似 (Int) -> String 的一系列函數(shù)類型來處理函數(shù)的聲明:

val onClick: () -> Unit = ...... 。`

這些類型具有與函數(shù)簽名相對應的特殊表示法,即它們的參數(shù)和返回值:

  • 所有函數(shù)類型都有一個圓括號括起來的參數(shù)類型列表以及一個返回類型:
(A, B) -> C

表示接受
類型分別為 A 與 B 兩個參數(shù)并返回一個 C 類型值的函數(shù)類型惜纸。 參數(shù)類型列表可以為空,如

() ->  A 古瓤。 Unit 返回類型不可省略。
  • 函數(shù)類型可以有一個額外的接收者類型,它在表示法中的點之前指定: 類型
A.(B) -> C 

表示可以在 A 的接收者對象上以一個 B 類型參數(shù)來調(diào)用并返回一個 C 類型值的函數(shù)主届。 帶有接收者的函
數(shù)字面值通常與這些類型一起使用橡庞。

A.(B) -> C 表示可
以在 A 的接收者對象上以一個 B 類型參數(shù)來調(diào)用并返回一個 C 類型值的函數(shù)。這句話不理解

//這樣的函數(shù)字面值的類型是一個帶有接收者的函數(shù)類型:
//下面是定義參數(shù)
sum : Int.(other: Int) -> Int
//該函數(shù)字面值可以這樣調(diào)用秉剑,就像它是接收者對象上的一個方法一樣:
1.sum(2)
  • 掛起函數(shù)屬于特殊種類的函數(shù)類型,它的表示法中有一個 suspend 修飾符 ,例如
suspend () -> Unit 或者 suspend A.(B) -> C 。

函數(shù)類型表示法可以選擇性地包含函數(shù)的參數(shù)名: (x: Int, y: Int) -> Point 床嫌。 這些名稱可用于表明參數(shù)的含義。

如需將函數(shù)類型指定為可空,請使用圓括號: ((Int, Int) -> Int)?贯要。
函數(shù)類型可以使用圓括號進行接合: (Int) -> ((Int) -> Unit)
箭頭表示法是右結(jié)合的, (Int) -> (Int) -> Unit 與前述示例等價,但不等于 ((Int) ->
(Int)) -> Unit京郑。
還可以通過使用類型別名給函數(shù)類型起一個別稱:

typealias ClickHandler = (Button, ClickEvent) -> Unit

函數(shù)類型實例化

有幾種方法可以獲得函數(shù)類型的實例:

  • 使用函數(shù)字面值的代碼塊,采用以下形式之一:
    • lambda 表達式: { a, b -> a + b } ,
    • 匿名函數(shù): fun(s: String): Int { return s.toIntOrNull() ?: 0 }
      帶有接收者的函數(shù)字面值可用作帶有接收者的函數(shù)類型的值。
  • 使用已有聲明的可調(diào)用引用:
    • 頂層绪抛、局部店雅、成員、擴展函數(shù): ::isOdd 、 String::toInt ,
    • 頂層痴鳄、成員、擴展屬性: List<Int>::size ,
    • 構(gòu)造函數(shù): ::Regex
      這包括指向特定實例成員的綁定的可調(diào)用引用: foo::toString 缸夹。
  • 使用實現(xiàn)函數(shù)類型接口的自定義類的實例:
class IntTransformer: (Int) -> Int {
override operator fun invoke(x: Int): Int = TODO()
}
val intFunction: (Int) -> Int = IntTransformer()

如果有足夠信息,編譯器可以推斷變量的函數(shù)類型:

val a = { i: Int -> i + 1 } // 推斷出的類型是 (Int) -> Int

帶與不帶接收者的函數(shù)類型非字面值可以互換,其中接收者可以替代第一個參數(shù),反之亦然痪寻。
例如,(A,
B) -> C 類型的值可以傳給或賦值給期待 A.(B) -> C 的地方,反之亦然:

val repeatFun: String.(Int) -> String = { times -> this.repeat(times) }
val twoParameters: (String, Int) -> String = repeatFun // OK
fun runTransformation(f: (String, Int) -> String): String {
return f("hello", 3)
}
val result = runTransformation(repeatFun) // OK

請注意,默認情況下推斷出的是沒有接收者的函數(shù)類型,即使變量是通過擴展函數(shù)引用來初始化的。 如需改變這點,請顯式指定變量類型

函數(shù)類型實例調(diào)用

函數(shù)類型的值可以通過其 invoke(......) 操作符調(diào)用: f.invoke(x) 或者直接 f(x) 虽惭。
如果該值具有接收者類型,那么應該將接收者對象作為第一個參數(shù)傳遞橡类。 調(diào)用帶有接收者的函數(shù)類型值 的另一個方式是在其前面加上接收者對象, 就好比該值是一個擴展函數(shù): 1.foo(2) ,例如

val stringPlus: (String, String) -> String = String::plus
val intPlus: Int.(Int) -> Int = Int::plus
println(stringPlus.invoke("<-", "->"))
println(stringPlus("Hello, ", "world!"))
println(intPlus.invoke(1, 1))
println(intPlus(1, 2))
println(2.intPlus(3)) // 類擴展調(diào)用

Lambda 表達式與匿名函數(shù)

lambda 表達式與匿名函數(shù)是“函數(shù)字面值”,即未聲明的函數(shù), 但立即做為表達式傳遞⊙看剑考慮下面的例子:

max(strings, { a, b -> a.length < b.length })

函數(shù) max 是一個高階函數(shù),它接受一個函數(shù)作為第二個參數(shù)顾画。 其第二個參數(shù)是一個表達式,它本身是一個函數(shù),即函數(shù)字面值,它等價于以下具名函數(shù):

fun compare(a: String, b: String): Boolean = a.length < b.length

Lambda 表達式語法

Lambda 表達式的完整語法形式如下:

val sum: (Int, Int) -> Int = { x: Int, y: Int -> x + y }

lambda 表達式總是括在花括號中, 完整語法形式的參數(shù)聲明放在花括號內(nèi),并有可選的類型標注, 函數(shù)體跟在一個 -> 符號之后取劫。如果推斷出的該 lambda 的返回類型不是 Unit ,那么該 lambda 主體中 的最后一個(或可能是單個)表達式會視為返回值。
如果我們把所有可選標注都留下,看起來如下:

val sum = { x, y -> x + y }

傳遞末尾的 lambda 表達式

在 Kotlin 中有一個約定:如果函數(shù)的最后一個參數(shù)是函數(shù),那么作為相應參數(shù)傳入的 lambda 表達式可以放在圓括號之外

val product = items.fold(1) { acc, e -> acc * e }

這種語法也稱為拖尾 lambda 表達式 研侣。
如果該 lambda 表達式是調(diào)用時唯一的參數(shù),那么圓括號可以完全省略:

run { println("...") }

it:單個參數(shù)的隱式名稱

一個 lambda 表達式只有一個參數(shù)是很常?的谱邪。如果編譯器自己可以識別出簽名,也可以不用聲明唯一的參數(shù)并忽略 -> 。 該參數(shù)會隱式聲明為 it :

//it 用在 lambda 表達式內(nèi)部來隱式引用其參數(shù)
ints.filter { it > 0 } // 這個字面值是“(it: Int) -> Boolean”類型的

從 lambda 表達式中返回一個值

我們可以使用限定的返回語法從 lambda 顯式返回一個值庶诡。 否則,將隱式返回最后一個表達式的值惦银。
因此,以下兩個片段是等價的

        ints.filter {
            val shouldFilter = it > 0
            shouldFilter
        }
        ints.filter {
            val shouldFilter = it > 0
            return@filter shouldFilter
        }

這一約定連同在圓括號外傳遞 lambda 表達式一起支持 LINQ-?格 的代碼:

strings.filter { it.length == 5 }.sortedBy { it }.map { it.toUpperCase() }

下劃線用于未使用的變量(自 1.1 起)

如果 lambda 表達式的參數(shù)未使用,那么可以用下劃線取代其名稱:

map.forEach { _, value -> println("$value!") }

在 lambda 表達式中解構(gòu)(自 1.1 起)

你可以對 lambda 表達式參數(shù)使用解構(gòu)聲明語法。 如果 lambda 表達式具有 Pair 類型(或者
Map.Entry 或任何其他具有相應 componentN 函數(shù)的類型)的參數(shù),那么可以通過將它們放在括號中來引入多個新參數(shù)來取代單個新參數(shù):

map.mapValues { entry -> "${entry.value}!" }
map.mapValues { (key, value) -> "$value!" }

注意聲明兩個參數(shù)和聲明一個解構(gòu)對來取代單個參數(shù)之間的區(qū)別:

{ a //-> ...... } //一個參數(shù)
{ a, b //-> ...... } // 兩個參數(shù)
{ (a, b) //-> ......   }// 一個解構(gòu)對
{ (a, b), c //-> ...... } // 一個解構(gòu)對以及其他參數(shù)

如果解構(gòu)的參數(shù)中的一個組件未使用,那么可以將其替換為下劃線,以避免編造其名稱:

map.mapValues { (_, value) -> "$value!" }

你可以指定整個解構(gòu)的參數(shù)的類型或者分別指定特定組件的類型:

map.mapValues { (_, value): Map.Entry<Int, String> -> "$value!" }
map.mapValues { (_, value: String) -> "$value!" }

匿名函數(shù)

上面提供的 lambda 表達式語法缺少的一個東西是指定函數(shù)的返回類型的能力末誓。
在大多數(shù)情況下,這是不必要的扯俱。因為返回類型可以自動推斷出來。然而,如果確實需要顯式指定,可以使用另一種語法: 匿名函數(shù) 基显。

fun(x: Int, y: Int): Int = x + y

匿名函數(shù)看起來非常像一個常規(guī)函數(shù)聲明,除了其名稱省略了蘸吓。其函數(shù)體可以是表達式(如上所示)或代碼塊:

fun(x: Int, y: Int): Int {
    return x + y
}

參數(shù)和返回類型的指定方式與常規(guī)函數(shù)相同,除了能夠從上下文推斷出的參數(shù)類型可以省略:

ints.filter(fun(item) = item > 0)

匿名函數(shù)的返回類型推斷機制與正常函數(shù)一樣:對于具有表達式函數(shù)體的匿名函數(shù)將自動推斷返回類型,而具有代碼塊函數(shù)體的返回類型必須顯式指定(或者已假定為 Unit )。
請注意,匿名函數(shù)參數(shù)總是在括號內(nèi)傳遞撩幽。 允許將函數(shù)留在圓括號外的簡寫語法僅適用于 lambda 表達式库继。
Lambda表達式與匿名函數(shù)之間的另一個區(qū)別是非局部返回的行為。一個不帶標簽的 return 語句總是在用 fun 關(guān)鍵字聲明的函數(shù)中返回窜醉。這意味著 lambda 表達式中的 return 將從包含它的函數(shù)返回,而匿名函數(shù)中的 return 將從匿名函數(shù)自身返回.

閉包

Lambda 表達式或者匿名函數(shù)(以及局部函數(shù)和對象表達式) 可以訪問其 閉包 ,即在外部作用域中聲明的變量宪萄。 在 lambda 表達式中可以修改閉包中捕獲的變量:

var sum = 0
ints.filter { it > 0 }.forEach {
    sum += it
}
print(sum)

帶有接收者的函數(shù)字面值

帶有接收者的函數(shù)類型,例如 A.(B) -> C ,可以用特殊形式的函數(shù)字面值實例化? 帶有接收者的函數(shù)字面值。
如上所述,Kotlin 提供了調(diào)用帶有接收者(提供接收者對象)的函數(shù)類型實例的能力榨惰。
在這樣的函數(shù)字面值內(nèi)部,傳給調(diào)用的接收者對象成為隱式的this,以便訪問接收者對象的成員而無需任何額外的限定符,亦可使用 this 表達式 訪問接收者對象拜英。這種行為與擴展函數(shù)類似,擴展函數(shù)也允許在函數(shù)體內(nèi)部訪問接收者對象的成員。這里有一個帶有接收者的函數(shù)字面值及其類型的示例,其中在接收者對象上調(diào)用了 plus :

val sum: Int.(Int) -> Int = { other -> plus(other) }

匿名函數(shù)語法允許你直接指定函數(shù)字面值的接收者類型琅催。 如果你需要使用帶接收者的函數(shù)類型聲明一個變量,并在之后使用它,這將非常有用居凶。

val sum = fun Int.(other: Int): Int = this + other

當接收者類型可以從上下文推斷時,lambda 表達式可以用作帶接收者的函數(shù)字面值。 One of the most important examples of their usage is type-safe builders:

    class HTML {
        fun body() { ...... }
    }
    fun html(init: HTML.() -> Unit): HTML {
        val html = HTML() // 創(chuàng)建接收者對象
        html.init()      // 將該接收者對象傳給該 lambda
        return html
    }
    html {              // 帶接收者的 lambda 由此開始
        body()          // 調(diào)用該接收者對象的一個方法
    }
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末藤抡,一起剝皮案震驚了整個濱河市侠碧,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌缠黍,老刑警劉巖弄兜,帶你破解...
    沈念sama閱讀 218,607評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異瓷式,居然都是意外死亡替饿,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,239評論 3 395
  • 文/潘曉璐 我一進店門贸典,熙熙樓的掌柜王于貴愁眉苦臉地迎上來视卢,“玉大人,你說我怎么就攤上這事廊驼【莨” “怎么了颊埃?”我有些...
    開封第一講書人閱讀 164,960評論 0 355
  • 文/不壞的土叔 我叫張陵,是天一觀的道長蝶俱。 經(jīng)常有香客問我,道長饥漫,這世上最難降的妖魔是什么榨呆? 我笑而不...
    開封第一講書人閱讀 58,750評論 1 294
  • 正文 為了忘掉前任,我火速辦了婚禮庸队,結(jié)果婚禮上积蜻,老公的妹妹穿的比我還像新娘。我一直安慰自己彻消,他們只是感情好竿拆,可當我...
    茶點故事閱讀 67,764評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著宾尚,像睡著了一般丙笋。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上煌贴,一...
    開封第一講書人閱讀 51,604評論 1 305
  • 那天御板,我揣著相機與錄音,去河邊找鬼牛郑。 笑死怠肋,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的淹朋。 我是一名探鬼主播笙各,決...
    沈念sama閱讀 40,347評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼础芍!你這毒婦竟也來了杈抢?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,253評論 0 276
  • 序言:老撾萬榮一對情侶失蹤者甲,失蹤者是張志新(化名)和其女友劉穎春感,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體虏缸,經(jīng)...
    沈念sama閱讀 45,702評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡鲫懒,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,893評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了刽辙。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片窥岩。...
    茶點故事閱讀 40,015評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖宰缤,靈堂內(nèi)的尸體忽然破棺而出颂翼,到底是詐尸還是另有隱情晃洒,我是刑警寧澤,帶...
    沈念sama閱讀 35,734評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站溉浙,受9級特大地震影響照捡,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜吃引,卻給世界環(huán)境...
    茶點故事閱讀 41,352評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望刽锤。 院中可真熱鬧镊尺,春花似錦、人聲如沸并思。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,934評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽宋彼。三九已至弄砍,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間宙暇,已是汗流浹背输枯。 一陣腳步聲響...
    開封第一講書人閱讀 33,052評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留占贫,地道東北人桃熄。 一個月前我還...
    沈念sama閱讀 48,216評論 3 371
  • 正文 我出身青樓,卻偏偏與公主長得像型奥,于是被迫代替她去往敵國和親瞳收。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,969評論 2 355