Kotlin语法(十七)-函数(Functions)

         参考原文:http://kotlinlang.org/docs/reference/functions.html

 

     声明函数(Function Declarations)

         在Kotlin中,使用“fun”关键字声明函数:

fun double(x: Int): Int {
}

 

     函数用法(Function Usage)

         顶层函数,直接通过函数名称直接访问:

val result = double(2)

 

         对于类成员函数,通过类实例加“.”方式使用:

Sample().foo() // create instance of class Sample and calls foo

 

       中缀标注(Infix notation)

         当函数满足下面几个条件,可以使用中缀方式调用:

         Ø  为成员函数或扩展函数

         Ø  有且只有一个参数

         Ø 使用“ 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)

 

       参数(Parameters)

         函数的参数定义格式: name type,参数间使用“,”分割,每个参数需要显式定义确定的类型:

fun powerOf(number: Int, exponent: Int) {
...
}

 

       默认实参(Default Arguments)

         参数可以设置默认值,该参数在使用的时候可以省略;可以减少重载的函数个数。

         语法:在类型类型后面使用“   =  ”添加默认值:

fun read(b: Array, 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
//override fun foo(i: Int = 2) { ... } //error,父类函数已设置默认值,重写函数,不能再设置默认值。
}

 

命名参数(Named Arguments)

         调用函数时,可以给传入的参数添加参数名;当一个函数有多个参数时,非常有用。

         如,有如下的一个函数:

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 = '_')

 

         注:当调用一个Java方法时,不可使用命名参数方式,Java不支持该语法。

 

       返回“Unit”类型函数

         若一个函数不需要返回任何有效值,那么它的返回类型为“ Unit”。“ Unit”类型只有一个值,即“ Unit”。另,可以不显示返回Unit:

fun printHello(name: String?): Unit {
    if (name != null)
        println("Hello ${name}")
    else
        println("Hi there!")
    // `return Unit` or `return` is optional
}

 

         返回的“Unit”也是可选的,下面的方式等同于返回“Unit”类型:

fun printHello(name: String?) {
    ...
}

 

       单表达式函数(Single-Expression functions)

         当函数返回一个单表达式的值,可以省略“{ }”直接将该单表达式使用“ =”跟在函数定义的后面:

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

 

         编译器可以推断出返回值类型时,函数定义时的返回值类型也可以省略:

fun double(x: Int) = x * 2

 

       显式返回类型(Explicit return types

         函数需要显式定义返回值类型,若没有则表示返回“Unit”。Kotlin不会去推断函数的返回类型当函数的函数体多行时,这种函数有比较复杂的实现,返回类型对于阅读者不是很明显(有时对编译器也不明确),故需要显示定义返回值类型。

 

       可变参数数量(Variable number of arguments (Varargs))

         使用“ vararg”关键字修饰参数,即可定义为可变数量参数(一般是最后一个参数):

fun  asList(vararg ts: T): List {
  val result = ArrayList()
  for (t in ts) // ts is an Array
    result.add(t)
    return result
}

         该函数可以接收不定个数参数:

val list = asList(1, 2, 3)

 

         在函数内部,被“vararg”修饰的参数实际上是一个数组(Array)。

 

         一个函数,只能有一个参数可以使用“ vararg”关键字修饰,一般放在最后一个参数。若不是最后一个参数,在使用时,其他的参数可以使用命名参数(Named Arguments)方式;或者函数有一个功能类型参数,可以在函数的后面定义一个Lambda表达式实现。
// vararg参数不是最后一个参数情况
fun asMultipleList(vararg ts: Int, multiple: Int): List {
val resultL = ArrayList()
    for(data in ts) {
        resultL.add(data * multiple)
     }
return resultL
}
//
var multiList = asMultipleList(1, 2, 3, multiple=2)
println(multiList)

//后面更有功能类型参数
fun showInfo(vararg infos: String, show: (info: String) -> Unit) {
for(info in infos) {
        show(info)
    }
}
//
showInfo("info1", "info2") {
println(it)
}

 

         调用一个“ vararg”函数时,可以一个一个值使用,如“ asList(1, 2, 3)”;也可以直接使用一个存在的数组数据,使用“ *”关键字:

val a = arrayOf(1, 2, 3)
val list = asList(-1, 0, *a, 4)

 

      函数范围(Function Scope)

         在Kotlin中,函数可以定义为顶层(top leve),表示不需要一个类去持有该函数。另外,还可以定义为局部,如类的成员函数,扩展函数。

局部函数(Local Functions)

         Kotlin支持局部函数,即在函数内部定义的函数:

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

  dfs(graph.vertices[0])
}

 

      成员函数(Member Functions)

         定义在一个类或对象中的,称为成员函数。

class Sample() {
  fun foo() { print("Foo") }
}

 

         成员函数,通过“.”方式访问:
Sample().foo() // creates instance of class Sample and calls foo

 

         更多关于成员函数信息,参考类与继承部分。

 

       泛型函数(Generic Functions)

         定义泛型参数的函数,更多详细信息参考 泛型部分。

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

 

       内联函数(Inline Functions)

         参考内联函数部分。

 

       扩展函数(Extension Functions)

         参考扩展函数部分。

 

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

         查考高阶函数和Lambda表达式部分。

 

       尾递归函数(Tail recursive functions)

         Kotlin支持尾递归函数,允许一些算法使用递归方式代替循环;而且不会有堆栈溢出的风险。使用“ tailrec”关键字修饰,编译器可以优化递归,生成一个快速、高效的循环版本。

tailrec fun findFixPoint(x: Double = 1.0): Double
        = if (x == Math.cos(x)) x else findFixPoint(Math.cos(x))

 

         等同于下面实现方式:

private fun findFixPoint(): Double {
    var x = 1.0
    while (true) {
        val y = Math.cos(x)
        if (x == y) return y
        x = y
    }
}

 

         使用“tailrec”修饰的尾递归函数需要满足下面几个条件:

        Ø  函数体最后一行执行代码需要是调用函数本身。

        Ø  不能在递归的函数后面还有其他的代码。

        Ø  递归部分不能放到“ try/catch/finally”中。



























你可能感兴趣的:(Kotlin)