参考:
函数(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])
}
成员函数
即类或对象中的方法。