Kotlin筆記 函數

Infix

Infix 函數是:

  • 如果函數是成員函數或者extension 函數
  • 如果只有一個參數
  • 標注了infix
// Define extension to Int
infix fun Int.shl(x: Int): Int {
...
}

// call extension function using infix notation

1 shl 2

// is the same as

1.shl(2)

函數默認值

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

如果子類要覆蓋父類的方法,函數聲明的時候需要沿用父類的默認值,不能重寫默認值

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

class B : A() {
    override fun foo(i: Int) { ... }  // no default value allowed
}

命名參數

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

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

Varargs

函數參數可以被標記為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
}

只有一個參數能被標記為vararg,如果vararg參數不是最后一個參數,其他參數只能通過命名參數來傳遞。

局部函數

局部函數是定義在函數內部的函數,它可以訪問外部函數的變量

fun dfs(graph: Graph) {
    fun dfs(current: Vertex, visited: Set<Vertex>) {
        if (!visited.add(current)) return
        for (v in current.neighbors)
            dfs(v, visited)
    }

    dfs(graph.vertices[0], HashSet())
}

泛型函數

泛型函數將泛型參數放在函數名之前

fun <T> singletonList(item: T): List<T> {
    // ...
}

Extension函數

向已有的對象添加函數,函數里的this代表對象

fun MutableList<Int>.swap(index1: Int, index2: Int) {
    val tmp = this[index1] // 'this' corresponds to the list
    this[index1] = this[index2]
    this[index2] = tmp
}

高階函數

高階函數將其他函數作為參數傳入

fun <T> lock(lock: Lock, body: () -> T): T {
    lock.lock()
    try {
        return body()
    }
    finally {
        lock.unlock()
    }
}

如果最后一個參數是函數,而且傳入的是lambda函數,則可以把lambda函數寫在括號外,如果傳入的是匿名函數,則不能寫在括號外:

lock (lock) {
    sharedResource.operation()
}

如果lambda函數只有一個參數,可以用it來指代

函數參數需要聲明函數的type:

fun <T> max(collection: Collection<T>, less: (T, T) -> Boolean): T? {
    var max: T? = null
    for (it in collection)
        if (max == null || less(max, it))
            max = it
    return max
}

函數類型里也可以指定參數名稱

val compare: (x: T, y: T) -> Int = ...

匿名函數

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

如果是單行的表達式,返回值的類型可以推導出,可以省略,如果是block,那么返回值的類型需要指定,否則就是Unit

lambda表達式的return是退出外圍的函數,而匿名函數的return是退出自己

閉包

lambda表達式和匿名函數都可以訪問外圍作用域的變量,與Java不同的是,Kotlin允許修改閉包里的變量(Java閉包的變量需要聲明為final)

帶Receiver的字面函數(好難理解)

你可以定義一個函數,指定這個函數的Receiver,Receiver為一個類

sum : Int.(other: Int) -> Int

然后在這個類的實例上調用這個函數

1.sum(2)

inline 函數

inline 之前

lock(l) { foo() }

inline 之后

inline fun lock<T>(lock: Lock, body: () -> T): T {
    // ...
}
==>
l.lock()
try {
    foo()
}
finally {
    l.unlock()
}

inline 會展開調用函數和lambda參數,如果不想lambda參數被展開,可以在lambda參數前加上noinline

inline fun foo(inlined: () -> Unit, noinline notInlined: () -> Unit) {
    // ...
}

lambda表達式中不允許使用不帶標簽的return語句(因為lambda中return是退出外圍的函數,這叫non-local return),但如果lambda是傳入到一個inline函數中,則可以return

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容