type: doc layout: reference category: "Syntax"
title: "Functions"
函数
函数声明
在Kotlin中,函数声明使用关键字 fun{: .keyword }
fun double(x: Int): Int {
}
参数
函数参数是使用Pascal符号定义,即 name: type.
参数用逗号隔开。每个参数必须显式类型。
fun powerOf(number: Int, exponent: Int) {
...
}
默认参数(缺省参数)
函数参数有默认值,当对应的参数是省略。与其他语言相比可以减少数量的过载。
fun read(b: Array<Byte>, off: Int = 0, len: Int = b.size) {
...
}
默认值定义使用后 = 类型的值。
参数命名
函数参数可以在调用函数时被命名。这是非常方便的,当一个函数有大量的参数或默认的。
给出下面的函数:
fun reformat(str: String,
normalizeCase: Boolean = true,
upperCaseFirstLetter: Boolean = true,
divideByCamelHumps: Boolean = false,
wordSeparator: Character = ' ') {
...
}
我们可以使用默认参数来调用这个
reformat(str)
然而,调用非默认时,调用类似于
reformat(str, true, true, false, '_')
使用命名参数我们可以使代码更具有可读性
reformat(str,
normalizeCase = true,
uppercaseFirstLetter = true,
divideByCamelHumps = false,
wordSeparator = '_'
)
如果我们不需要所有的参数
reformat(str, wordSeparator = '_')
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
返回类型声明也是可选的。上面的代码等同于
fun printHello(name: String?) {
...
}
单个表达式函数
当一个函数返回单个表达式,花括号可以省略并且主体由 =符号之后指定
fun double(x: Int): Int = x * 2
显式地声明返回类型可选时,这可以由编译器推断
fun double(x: Int) = x * 2
显式地返回类型
在某些情况下,一个显式地返回类型是必需的:
函数表达式是公共的或是受保护的.这些都被认为是公共API的一部分.由于没有显式地返回类型使得它有可能更容易更改类型.这就是为什么显式地类型都需要相同的原因属性.
函数模块体必须显式地指定返回类型,除非是用于返回
Unit
,在这种情况下,它是可选的。Kotlin不推断返回类型与函数在模块体的功能,因为这些功能可能在模块体有复杂的控制流程,返回类型将不明显的阅读器(有时甚至为编译器).
可变的参数(可变参数)
函数的最后一个参数可以使用'vararg`注释
fun asList<T>(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)
内部函数vararg
类型T
是可见的arrayT
,即ts
变量在上面的例子是Array<out T>
类型。
只有一个参数可以标注为 vararg
.这可能是最后一个参数或前一个最后的,如果最后一个参数类型(允许一个lambda括号外传递)
当我们调用vararg
函数,我们可以一个接一个传递参数,例如 asList(1, 2, 3)
或者,如果我们已经有了一个数组并希望将其内容传递给函数,我们使用spread 操作符(在数组前面加*
)
val a = array(1, 2, 3)
val list = asList(-1, 0, *a, 4)
函数作用域(函数范围)
在Kotlin中,函数可以在文件头部声明,这意味着您不需要创建一个类来保存一个函数,类似的语言如Java,C#或Scala。此外除了头部函数功能,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())
}
局部函数可以访问外部函数的局部变量(即,关闭),所以在上面的例子,the visited是局部变量.
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])
}
从外部函数使用局部函数甚至可以返回正确的表达式
fun reachable(from: Vertex, to: Vertex): Boolean {
val visited = HashSet<Vertex>()
fun dfs(current: Vertex) {
// here we return from the outer function:
if (current == to) return@reachable true
// And here -- from local function:
if (!visited.add(current)) return
for (v in current.neighbors)
dfs(v)
}
dfs(from)
return false // if dfs() did not return true already
}
成员函数
成员函数是一个函数,定义在一个类或对象里
class Sample() {
fun foo() { print("Foo") }
}
成员函数调用点符号
Sample().foo() // creates instance of class Sample and calls foo
有关类信息和主要成员查看Classes 和 Inheritance
重载函数
函数可以有泛型参数,在函数之后使用尖括号和在参数值之前。
fun singletonArray<T>(item: T): Array<T> {
return Array<T>(1, {item})
}
有关重载函数更多信息请查看 Generics
内联函数
内联函数解释 here
扩展函数
扩展函数解释 their own section
高阶函数和Lambdas表达式
高阶函数和Lambdas表达式中有详细解释 their own section
函数用途
调用函数使用传统的方法
val result = double(2)
调用成员函数使用点符号
Sample().foo() // create instance of class Sample and calls foo
插入表示法
函数还可以用中缀表示法,当
他们是成员函数 或者 扩展函数
他们有一个参数
// Define extension to Int
fun Int.shl(x: Int): Int {
...
}
// call extension function using infix notation
1 shl 2
// is the same as
1.shl(2)
翻译By Jacky Xu