函數(shù)
函數(shù)的聲明和用法 省略
參數(shù)
- 函數(shù)參數(shù)使用 Pascal 表示法定義,即 name: type。參數(shù)用逗號(hào)隔開。每個(gè)參數(shù)必須有顯式類型:
fun powerOf(number: Int, exponent: Int) { /*……*/ }
- 默認(rèn)參數(shù)
函數(shù)參數(shù)可以有默認(rèn)值,當(dāng)省略相應(yīng)的參數(shù)時(shí)使用默認(rèn)值。與其他語言相比,這可以減少重載數(shù)量:
fun read(b: Array<Byte>, off: Int = 0, len: Int = b.size) { /*……*/ }
默認(rèn)值通過類型后面的 = 及給出的值來定義。
覆蓋方法總是使用與基類型方法相同的默認(rèn)參數(shù)值。 當(dāng)覆蓋一個(gè)帶有默認(rèn)參數(shù)值的方法時(shí),必須從簽名中省略默認(rèn)參數(shù)值:
open class A {
open fun foo(i: Int = 10) { /*……*/ }
}
class B : A() {
override fun foo(i: Int) { /*……*/ } // 不能有默認(rèn)值
}
如果一個(gè)默認(rèn)參數(shù)在一個(gè)無默認(rèn)值的參數(shù)之前,那么該默認(rèn)值只能通過使用調(diào)用該函數(shù)來使用:
fun foo(bar: Int = 0, baz: Int) { /*……*/ }
foo(baz = 1) // 使用默認(rèn)值 bar = 0
如果在默認(rèn)參數(shù)之后的最后一個(gè)參數(shù)是 [lambda 表達(dá)式]那么它既可以作為命名參數(shù)在括號(hào)內(nèi)傳入,也可以在[括號(hào)外]傳入:
fun foo(bar: Int = 0, baz: Int = 1, qux: () -> Unit) { /*……*/ }
foo(1) { println("hello") } // 使用默認(rèn)值 baz = 1
foo(qux = { println("hello") }) // 使用兩個(gè)默認(rèn)值 bar = 0 與 baz = 1
foo { println("hello") }
- 命名參數(shù)
可以在調(diào)用函數(shù)時(shí)使用命名的函數(shù)參數(shù)。當(dāng)一個(gè)函數(shù)有大量的參數(shù)或默認(rèn)參數(shù)時(shí)這會(huì)非常方便。
給定以下函數(shù):
fun reformat(str: String,
normalizeCase: Boolean = true,
upperCaseFirstLetter: Boolean = true,
divideByCamelHumps: Boolean = false,
wordSeparator: Char = ' ') {
/*……*/
}
我們可以使用默認(rèn)參數(shù)來調(diào)用它:
reformat(str)
對(duì)于 JVM 平臺(tái):在調(diào)用 Java 函數(shù)時(shí)不能使用命名參數(shù)語法,因?yàn)?Java 字節(jié)碼并不總是保留函數(shù)參數(shù)的名稱。
返回 Unit 的函數(shù)
即Java中無返回值的函數(shù)
單表達(dá)式函數(shù)
當(dāng)函數(shù)返回單個(gè)表達(dá)式時(shí),可以省略花括號(hào)并且在 = 符號(hào)之后指定代碼體即可:
fun double(x: Int): Int = x * 2
當(dāng)返回值類型可由編譯器推斷時(shí),顯式聲明返回類型是可選的:
fun double(x: Int) = x * 2
函數(shù)作用域
在 Kotlin 中函數(shù)可以在文件頂層聲明,這意味著你不需要像一些語言如 Java、C# 或 Scala 那樣需要?jiǎng)?chuàng)建一個(gè)類來保存一個(gè)函數(shù)。此外除了頂層函數(shù),Kotlin 中函數(shù)也可以聲明在局部作用域、作為成員函數(shù)以及擴(kuò)展函數(shù)。
Kotlin 支持局部函數(shù),即一個(gè)函數(shù)在另一個(gè)函數(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 dfs(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ù)
泛型函數(shù)
函數(shù)可以有泛型參數(shù),通過在函數(shù)名前使用尖括號(hào)指定:
fun <T> singletonList(item: T): List<T> { /*……*/ }
高階函數(shù)與 lambda 表達(dá)式
lambda表達(dá)式語法格式如下:
(parameters)-> expression
or
(parameters) -> {statements;}
- 以下是lambda表達(dá)式的重要特征:
1.可選類型聲明:不需要聲明參數(shù)類型,編譯器可以統(tǒng)一識(shí)別參數(shù)值。
2.可選的參數(shù)圓括號(hào):一個(gè)參數(shù)無需定義圓括號(hào),但多個(gè)參數(shù)需要定義圓括號(hào)。
3.可選的大括號(hào):如果主體包含了一個(gè)語句,就不需要使用大括號(hào)。
4.可選的返回關(guān)鍵字:如果主體只有一個(gè)表達(dá)式返回值則編譯器會(huì)自動(dòng)返回值,大括號(hào)需要指定明表達(dá)式返回了一個(gè)數(shù)值。
lambda 表達(dá)式總是括在花括號(hào)中, 完整語法形式的參數(shù)聲明放在花括號(hào)內(nèi),并有可選的類型標(biāo)注, 函數(shù)體跟在一個(gè) -> 符號(hào)之后。如果推斷出的該 lambda 的返回類型不是 Unit,那么該 lambda 主體中的最后一個(gè)(或可能是單個(gè))表達(dá)式會(huì)視為返回值
如果我們把所有可選標(biāo)注都留下,看起來如下
val sum = { x, y -> x + y }
- 將 lambda 表達(dá)式傳給最后一個(gè)參數(shù)
在 Kotlin 中有一個(gè)約定:如果函數(shù)的最后一個(gè)參數(shù)是函數(shù),那么作為相應(yīng)參數(shù)傳入的 lambda 表達(dá)式可以放在圓括號(hào)之外:
val product = items.fold(1) { acc, e -> acc * e }
如果該 lambda 表達(dá)式是調(diào)用時(shí)唯一的參數(shù),那么圓括號(hào)可以完全省略:
run { println("...") }
- 從 lambda 表達(dá)式中返回一個(gè)值
我們可以使用限定的返回語法從 lambda 顯式返回一個(gè)值。 否則,將隱式返回最后一個(gè)表達(dá)式的值。
因此,以下兩個(gè)片段是等價(jià)的:
ints.filter {
val shouldFilter = it > 0
shouldFilter
}
ints.filter {
val shouldFilter = it > 0
return@filter shouldFilter
}
- 下劃線用于未使用的變量(自 1.1 起)
如果 lambda 表達(dá)式的參數(shù)未使用,那么可以用下劃線取代其名稱:
map.forEach { _, value -> println("$value!") }