我们需要掌握的Kotlin之各种函数

Kotlin的函数可以定义在文件顶部,也就是说不需要创建一个类来持有一个函数。另外,Kotlin函数还包括:本地函数、成员函数、扩展函数、内联函数、高阶函数、泛型函数、递归函数。

一、本地函数

本地函数是函数内部包含另一个函数,也就是函数嵌套,示例代码如下:

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])
}

二、成员函数

成员函数是定义在类内部,与Java一样,示例代码如下:

class Sample() {
    fun hello() { print("Hello World") }
}

成员函数可以使用点引用来调用:

Sample().hello()

三、泛型函数

泛型函数是指函数中,参数或返回值类型定义成泛型,使用T表示:

fun <T> singletonList(item: T): List<T> { 
  print("This is generic function")
}

四、内联函数

内存分配(包含函数对象和类)和虚函数调用,会带来运行时开销。但是,这些开销可以通过内联的lambda表达式来消除。对于编译器来说,我们需要使用inline修饰符来标识:

inline fun <T> lock(lock: Lock, body: () -> T): T {
  print("This is an inline function")
}

内联修饰符会影响函数本身和lambda传递,这些都要内联到调用端。内联可能会引起代码增长。但是,如果我们使用恰当(避免在庞大函数中使用),它可以提升性能。

1、noinline

如果,我们只想某个lambda表达式内联,而不是整个函数内联。我们可以使用inlined和ontInlined修饰符来标识:

inline fun hello(inlined: () -> Unit, noinline notInlined: () -> Unit) {
  print("This is inlined lambda")
}

2、crossinline

有些函数传递lambda参数不是通过函数体本身,而是从另一个执行体,比如本地对象或者嵌套函数。这种情况下,non-local控制流也不允许出现在lambda表达式中。这时,需要使用crossline修饰符来标识:

inline fun f(crossinline body: () -> Unit) {
    val f = object: Runnable {
        override fun run() = body()
    }
}

3、inline properties

内联修饰符可以用于属性的访问,我们可以这样注解单个属性:

val foo: Foo
    inline get() = Foo()

var bar: Bar
    get() = ...
    inline set(v) { ... }

五、扩展函数

Kotlin提供类的扩展功能,不必用继承类的方法或者使用装饰者的设计模式。可以通过extensions来特殊声明,Kotlin支持扩展函数和扩展属性。声明一个扩展函数,我们需要在名称前面加一个接收类型。如下代码是往MutableList<Int>添加swap功能:

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

扩展函数中的this关键字对应接收者类型。现在,我们可以调用MutableList<Int>中的swap方法:

val l = mutableListOf(1, 2, 3)
l.swap(0, 2)

六、高阶函数

高阶函数是把函数作为参数或者返回值的函数。示例代码如下:

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
}

七、递归函数 

Kotlin支持特色功能性编程——尾递归。可以运行算法使用loop循环来代替递归函数,这样可以避免栈溢出。当使用tailrec修饰符时,遇到特定格式,编译器会优化递归,改成快速高效的基于loop循环的版本。示例代码如下:

tailrec fun findFixPoint(x: Double = 1.0): Double
        = if (Math.abs(x - Math.cos(x)) < eps) x else findFixPoint(Math.cos(x))
发布了63 篇原创文章 · 获赞 179 · 访问量 18万+

猜你喜欢

转载自blog.csdn.net/u011686167/article/details/90580947