zwvista

导航

Kotlin语言学习笔记(4)

函数

// 函数定义及调用
fun double(x: Int): Int {
    return 2*x
}
val result = double(2)
// 调用方法
Stream().read() // create instance of class Stream and call read()
// 参数语法
fun powerOf(number: Int, exponent: Int): Int { /*...*/ }
// 参数声明时可以带拖尾逗号
fun powerOf(
    number: Int,
    exponent: Int, // trailing comma
) { /*...*/ }
// 缺省参数
fun read(
    b: ByteArray,
    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 is 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(qux = { println("hello") }) // Uses both default values bar = 0 and 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(
    "String!",
    false,
    upperCaseFirstLetter = false,
    divideByCamelHumps = true,
    '_'
)
reformat("This is a long String!")
reformat("This is a short String!", upperCaseFirstLetter = false, 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)
val a = intArrayOf(1, 2, 3) // IntArray is a primitive type array
val list = asList(-1, 0, *a.toTypedArray(), 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())
}
// 局部函数可以访问外部函数的变量,即可以用作闭包(closure)
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> { /*...*/ }
// 尾部递归函数
val eps = 1E-10 // "good enough", could be 10^-15
tailrec fun findFixPoint(x: Double = 1.0): Double =
    if (Math.abs(x - Math.cos(x)) < eps) x else findFixPoint(Math.cos(x))
// 相当于
val eps = 1E-10 // "good enough", could be 10^-15
private fun findFixPoint(): Double {
    var x = 1.0
    while (true) {
        val y = Math.cos(x)
        if (Math.abs(x - y) < eps) return x
        x = Math.cos(x)
    }
}

高阶函数和lambda表达式(Higher-Order Functions and Lambdas)

高阶函数:将函数作为参数或返回值的函数。
可以使用函数引用(function references)将函数作为参数传给函数
lambda表达式的特点

  • lambda表达式使用尖括号
  • 参数(类型可省略)位于->符号之前
  • 函数体位于->符号之后
  • 不能指定返回类型
  • lambda表达式参数位于最后时可以脱离小括号
  • return语句将跳出包含lambda表达式的外围函数
    匿名函数(Anonymous Functions)
  • 没有函数名的函数
  • 可以指定返回类型
  • 必须包含在小括号中
  • return语句跳出匿名函数自身
    高阶函数和匿名函数统称函数字面量(function literal)。
// 高阶函数
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
}
// 使用lambda表达式
val items = listOf(1, 2, 3, 4, 5)
// Lambdas are code blocks enclosed in curly braces.
items.fold(0, { 
    // When a lambda has parameters, they go first, followed by '->'
    acc: Int, i: Int -> 
    print("acc = $acc, i = $i, ") 
    val result = acc + i
    println("result = $result")
    // The last expression in a lambda is considered the return value:
    result
})
// Parameter types in a lambda are optional if they can be inferred:
val joinedToString = items.fold("Elements:", { acc, i -> acc + " " + i })
// Function references can also be used for higher-order function calls:
val product = items.fold(1, Int::times)
/*
acc = 0, i = 1, result = 1
acc = 1, i = 2, result = 3
acc = 3, i = 3, result = 6
acc = 6, i = 4, result = 10
acc = 10, i = 5, result = 15
joinedToString = Elements: 1 2 3 4 5
product = 120
*/
val result = lock(lock, { sharedResource.operation() })
// 函数字面量和高阶函数
max(strings, { a, b -> a.length < b.length })
// 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
}

posted on 2017-06-08 22:42  zwvista  阅读(254)  评论(0编辑  收藏  举报