Kotlin語言學習筆記(4)

函數

// 函數定義及調用
fun double(x: Int): Int {
    return 2*x
}
val result = double(2)
// 調用方法
Sample().foo() // create instance of class Sample and call foo
// 參數語法
fun powerOf(number: Int, exponent: Int) {
...
}
// 缺省參數
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 foo(bar: Int = 0, baz: Int) { /* ... */ }
foo(baz = 1) // The default value bar = 0 is used
// 缺省參數以後還能夠有 lambda 參數
fun foo(bar: Int = 0, baz: Int = 1, qux: () -> Unit) { /* ... */ }
foo(1) { println("hello") } // Uses the default value baz = 1 
foo { println("hello") }    // Uses both default values bar = 0 and baz = 1
// 具名參數 
fun reformat(str: String,
             normalizeCase: Boolean = true,
             upperCaseFirstLetter: Boolean = true,
             divideByCamelHumps: Boolean = false,
             wordSeparator: Char = ' ') {
...
}
reformat(str)
reformat(str, true, true, false, '_')
reformat(str,
    normalizeCase = true,
    upperCaseFirstLetter = true,
    divideByCamelHumps = false,
    wordSeparator = '_'
)
reformat(str, wordSeparator = '_')
// 展開(spread)運算符
fun foo(vararg strings: String) { /* ... */ }
foo(strings = *arrayOf("a", "b", "c"))
// 返回類型爲Unit的函數
fun printHello(name: String?): Unit {
    if (name != null)
        println("Hello ${name}")
    else
        println("Hi there!")
    // `return Unit` or `return` is optional
}
fun printHello(name: String?) {
    ...
}
// 表達式函數
fun double(x: Int): Int = x * 2
fun double(x: Int) = x * 2
// varargs
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
}
val list = asList(1, 2, 3)
val a = arrayOf(1, 2, 3)
val list = asList(-1, 0, *a, 4)
// 擴展函數的中綴表示法
infix fun Int.shl(x: Int): Int {
    // ...
}
// calling the function using the infix notation
1 shl 2
// is the same as
1.shl(2)
// 成員函數的中綴表示法
class MyStringCollection {
    infix fun add(s: String) { /* ... */ }
    
    fun build() {
        this add "abc"   // Correct
        add("abc")       // Correct
        add "abc"        // Incorrect: the receiver must be specified
    }
}
// 局部函數
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 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])
}
// 成員函數
class Sample() {
    fun foo() { print("Foo") }
}
Sample().foo() // creates instance of class Sample and calls foo
// 泛型函數
fun <T> singletonList(item: T): List<T> {
    // ...
}

高階函數和lambda表達式(Higher-Order Functions and Lambdas)

高階函數:將函數做爲參數或返回值的函數。
lambda表達式的特色html

  • lambda表達式使用尖括號
  • 參數(類型可省略)位於->符號以前
  • 函數體位於->符號以後
  • 不能指定返回類型
  • lambda表達式參數位於最後時能夠脫離小括號
  • return語句將跳出包含lambda表達式的外圍函數
    匿名函數(Anonymous Functions)
  • 沒有函數名的函數
  • 能夠指定返回類型
  • 必須包含在小括號中
  • return語句跳出匿名函數自身
    高階函數和匿名函數統稱函數字面量(function literal)。
// 高階函數
fun <T> lock(lock: Lock, body: () -> T): T {
    lock.lock()
    try {
        return body()
    }
    finally {
        lock.unlock()
    }
}
// 使用函數引用(function references)將函數做爲參數傳給函數
fun toBeSynchronized() = sharedResource.operation()
val result = lock(lock, ::toBeSynchronized)
// 使用lambda表達式
val result = lock(lock, { sharedResource.operation() })
// lambda表達式是最後一個參數時,括弧能夠省略
lock (lock) {
    sharedResource.operation()
}
// 高階函數map
fun <T, R> List<T>.map(transform: (T) -> R): List<R> {
    val result = arrayListOf<R>()
    for (item in this)
        result.add(transform(item))
    return result
}
val doubled = ints.map { value -> value * 2 }
// 只有一個參數時可使用隱式參數it
ints.map { it * 2 }
// LINQ風格的代碼
strings.filter { it.length == 5 }.sortBy { it }.map { it.toUpperCase() }
// 不須要使用的參數能夠用下劃線表示
map.forEach { _, value -> println("$value!") }
// lambda表達式語法
val sum = { x: Int, y: Int -> x + y }
val sum: (Int, Int) -> Int = { x, y -> x + y }
ints.filter { it > 0 } // this literal is of type '(it: Int) -> Boolean'
// lambda表達式隱式返回最後一個表達式的值
// 兩段代碼效果相同
ints.filter {
    val shouldFilter = it > 0 
    shouldFilter
}
ints.filter {
    val shouldFilter = it > 0 
    return@filter shouldFilter
}
// 匿名函數
fun(x: Int, y: Int): Int = x + y
fun(x: Int, y: Int): Int {
    return x + y
}
// 使用匿名函數
// 參數類型可省略
ints.filter(fun(item) = item > 0)
// 閉包(Closures)
var sum = 0
ints.filter { it > 0 }.forEach {
    sum += it
}
print(sum)
// 帶 receiver(隱含調用方)的函數字面量
sum : Int.(other: Int) -> Int
1.sum(2)
val sum = fun Int.(other: Int): Int = this + other
// String.(Int) -> Boolean 與 (String, Int) -> Boolean 相互兼容
val represents: String.(Int) -> Boolean = { other -> toIntOrNull() == other }
println("123".represents(123)) // true
fun testOperation(op: (String, Int) -> Boolean, a: String, b: Int, c: Boolean) =
    assert(op(a, b) == c)
testOperation(represents, "100", 100, true) // OK
// 經過上下文推導 receiver
class HTML {
    fun body() { ... }
}
fun html(init: HTML.() -> Unit): HTML {
    val html = HTML()  // create the receiver object
    html.init()        // pass the receiver object to the lambda
    return html
}
html {       // lambda with receiver begins here
    body()   // calling a method on the receiver object
}
相關文章
相關標籤/搜索