参考:

函数(Function)

Kotlin使用名称函数(function)而非方法(method),我想是为了与Java方法作出区分,和C语言类似函数可以单独定 义和使用,不依赖于类与对象,而Java中的方法只存在于某个类中。由于Kotlin与Java是兼容的,因此在类中定义的函数仍然 适用于方法这个语义。

Kotlin使用fun来声明函数:

    fun double(x: Int): Int {
        return 2*x
    }

参数

函数参数使用Pascal的表示来定义,即name: type

默认参数值

函数参数可以有默认值,这样在调用函数时如果没有传入某个参数,那么便使用改参数对应的默认值,这样可以从某种程度上减少 方法重载(overload)。在参数类型后,使用=后跟上一个值来定义默认值。

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

对于类中方法的重写(override),子类方法总是使用与父类方法相同的默认值,并且子类方法签名中不能有默认值。

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

命名参数值

看到这里,发现这和Python语法太TM像了。默认参数传递是根据位置来判断的,称为位置参数,由于有了默认参数,可能调用时 传入的参数比签名中的少,例如调用时,一个参数值前面有一个忽略了的默认参数,该参数值的位置被提前了,这时根据位置就无 法判断参数值与参数的对应关系,此时需要将该非默认参数值使用参数名明确标出。

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

该函数可以这样调用:

    reformat(str)

    reformat(str, wordSeparator = '_')

命名参数调用方式不能用于Java方法,因为Java字节码并不总是保存参数名。

不定长参数

不定长参数(Variable number of arguments)使用关键词vararg定义,传入的参数可以使用展开(spread)操作符得到:

    fun foo(vararg strings: String) { /* ... */ }
    
    foo(strings = *arrayOf("a", "b", "c"))
    foo(strings = "a") // Not required for a single value

参数列表中,只能有一个参数是不定长的。如果不定长参数不是最后一个参数,那么随后的参数需要使用命名参数进行传递,或者 如果随后的参数是一个函数类型那么,可以通过在参数表括弧外传递lambda表达式。

如果已经有了一个数组作为传递的参数值, 展开操作符还可以这样使用:

    foo("1", "2", strings = *arrayOf("a", "b", "c"))

返回单元(Unit)的函数

如果函数不返回有用的值,那么其返回值就是Unit。Unit是只有一个值的类型,该值即Unit。

单一表达式函数

当一个函数返回一个单一表达式时,函数体的花括弧可以去掉,并且将表达式以赋值的形式赋值给函数定义。

    fun double(x: Int): Int = x * 2

返回类型可以忽略,因为编译器可以从表达式推断出:

    fun double(x: Int) = x * 2

中缀表示

当一个函数满足以下条件时可以使用中缀表达式进行调用:

  • 属于成员方法或扩展函数
  • 有单一参数
  • 使用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)

函数作用域

Kotlin中除了可以定义为文件中的顶级函数外,还可以定义为局部函数,成员函数以及扩展函数。

局部函数

定义在另一个函数中的一个函数,它可以访问外部函数的局部变量:

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

成员函数

即类或对象中的方法。

其它类型函数