函数
Kotlin 函数 使用 fun
关键字声明:
函数用法
函数使用标准的方式调用:
调用成员函数使用点符号:
参数
函数参数使用 Pascal 表示法定义 - name: type 。参数用逗号分隔,并且每个参数必须显式指定类型:
在声明函数参数时,可以使用尾随逗号:
默认参数
函数参数可以有默认值,当跳过相应的实参时,将使用默认值。这减少了重载的数量:
默认值通过在类型后附加 =
来设置。
重写函数时总是使用基函数的默认参数值。当重写一个具有默认参数值的函数时,必须在签名中省略默认参数值:
如果默认参数出现在没有默认值的参数之前,只有通过具名参数调用函数时才能使用默认值:
如果默认参数之后的最后一个参数是一个lambda ,可以将其作为具名函数传递,或者在括号外传递:
具名参数
调用函数时,可以给一个或多个参数命名。当一个函数有很多参数且难以将值与参数关联时,这尤其有用,特别是当参数是布尔值或 null
值时。
在函数调用中使用具名函数时,可以随意更改参数的顺序。如果想使用它们的默认值,可以直接省略这些参数。
考虑具有四个默认值参数的 reformat()
函数。
调用此函数时,不必为所有参数命名:
可以跳过所有带默认值的参数:
也可以跳过特定的带默认值的参数,而不是全部省略。然而,在第一个跳过的参数之后,必须为所有后续参数命名:
可以使用 展开
运算符为可变数量的参数 (vararg
)传递具名函数:
返回 Unit
的函数
如果函数不返回有用的值,其返回类型为 Unit
。 Unit
是只有一个值的类型——Unit
。这个值不必显式返回:
Unit
返回类型的声明也是可选的。上述代码等价于:
单表达式函数
当函数体只包含一个表达式时,可以省略花括号,并在 =
符号之后指定函数体:
当返回类型可以被编译器推断时, 显式声明返回类型是可选的:
显式返回类型
对于具有块体的函数,必须始终显式指定返回类型,除非它们返回 Unit
, 在这种情况下,指定返回类型是可选的。
Kotlin 不会为具有块体的函数推断返回类型,因为此类函数的控制流可能很复杂,返回类型对于读者(有时甚至对于编译器)来说可能并不明显。
可变数量的参数(varargs)
你可以用 vararg
修饰符标记函数的一个参数(通常是最后一个):
在这种情况下,你可以向函数传递可变数量的参数:
在函数内部,类型为 T
的 vararg
参数可以作为 T
类型的数组使用,如上例所示,其中 ts
变量的类型为 Array<out T>
。
只有一个参数可以标记为 vararg
。 如果 vararg
参数不是列表中的最后一个参数,则可以使用具名函数语法传递后续参数的值,或者如果参数具有函数类型,则可以通过在括号外传递 lambda 来实现。
调用 vararg
函数时,你可以单独传递参数,例如 asList(1, 2, 3)
。 如果已经有一个数组并且想将其内容传递给函数,请使用展开操作符(在数组前加 *
):
如果想将一个原始类型数组传递给 vararg
,需要使用 toTypedArray()
函数将其转换为常规(类型化)数组:
中缀表示符号(Infix Notation)
用 infix
关键字标记的函数也可以使用中缀符号调用(省略点号和调用的括号)。中缀函数必须满足以下要求:
注意中缀函数总是要求指定接收者和参数。当你使用中缀符号调用当前接收者的函数时,需要显式使用 this
。这是为了确保解析无歧义。
函数作用域
Kotlin 中的函数可以在文件的顶层声明,这意味着你不需要像在 Java、C# 和 Scala 等语言中那样创建一个类来容纳函数(Scala 3 起提供顶层定义 【Scala 3 顶层定义】)。 除了顶层函数,Kotlin 函数还可以在本地声明为成员函数和扩展函数。
局部函数
Kotlin 支持局部函数,即在其他函数内部定义的函数:
局部函数可以访问外部函数的局部变量(闭包)。在上面的例子中, visited
可以是一个局部变量:
成员函数
成员函数是在类或对象内部定义的函数:
成员函数使用点符号进行调用:
泛型函数
函数可以具有泛型参数,使用尖括号在函数名之前指定:
有关泛型函数的更多信息,请参阅泛型。
尾递归函数
Kotlin支持一种称为尾递归的函数式编程风格。 对于一些通常使用循环的算法,您可以使用递归函数代替,而不会出现堆栈溢出的风险。 当函数标记为tailrec
修饰符并满足所需的形式条件时,编译器会优化递归,留下一个快速而高效的基于循环的版本:
这段代码计算了余弦的fixpoint
,这是一个数学常量。 它简单地重复调用Math.cos
,从1.0
开始,直到结果不再改变,对于指定的eps
精度,得到的结果是0.7390851332151611
。 生成的代码相当于这种更传统的风格:
要成为tailrec
修饰符的候选项,函数必须在执行的最后操作中调用自身。 在递归调用之后不能使用尾递归,不能在try
/catch
/finally
块内使用,也不能在开放函数中使用。 目前,Kotlin支持JVM和Kotlin/Native的尾递归。
另请参阅: