函数声明
Kotlin中的函数使用fun关键字声明,函数参数使用Pascal表示法定义,即attribute: Type。每个参数必须有显示类型。
单表达式函数:当函数返回单个表达式时,可以省略花括号并且在=符号之后指定代码体即可。注意:Kotlin不推断具有代码块体的函数的返回类型,所以若具有代码块体的函数只有在返回Unit类型时,可以省略返回值类型。以下截图展示这一区别👇
上图中,若不显示著名函数返回类型为Int,就会报错。
(如果一个函数不返回任何有用的值,他的返回类型是Unit。所以return Unit
与return
等同,并且是可选的)
* 可以使用类型别名给函数类型起一个别称:
参数
Kotlin中,函数参数可以有默认值,当省略相应的参数时使用默认值。**与其他语言相比,这可以减少重载数量。**如果一个默认参数在一个无默认值的参数之前,那么该默认值只能通过使用具名参数调用该函数来使用。
覆盖方法总是使用与基类型方法相同的默认参数,且必须从签名中省略默认参数值。
可变数量参数:参数前用vararg修饰,此时参数被当作数组来处理。
中缀表示法
标有infix关键字的函数也可以使用中缀表示法调用。中缀函数必须满足以下要求:
1. 它们必须是成员函数或扩展函数;
2. 它们必须只有一个参数;
3. 其参数不得接受可变数量的参数且不能有默认值。
中缀函数举例:until, xor, union, ... 🌰 :0 until 10
, xs union ys
, true xor true
还有to
:val map = mapOf("key1" to 1, "key2" to 2, "key3" to 3, "key4" to 3)
这里to声明了map中key与value的关系,比java中的写法简洁了很多,Kotlin标准库中对to函数的生命如下:
public infix fun <A,B> A.to(that: B): Pair<A, B> = Pair(this, that)
局部函数
一个函数在另一个函数内部,局部函数可以访问外部函数(即闭包)的局部变量,🌰 :
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])
}
成员函数
成员函数是在类或对象内部定义的函数,🌰 :
class Sample{
fun foo(){ print("Foo")}
}
//调用:
Sample().foo() // 创建类Sample实例并调用foo
泛型函数
函数可以有泛型参数,通过在函数名前使用尖括号指定,🌰 :
fun <T> singletonList(item: T): List<T> { /*...*/ }
高阶函数和Lambda表达式
Kotlin语言天然支持了部分函数式特性。函数式语言一个典型的特性在于函数是头等公民--我们不仅可以像
类一样在顶层直接定义一个函数,也可以在一个函数内部定义一个函数。在上面的局部函数中有例子。
此外,我们还可以直接将函数像普通变量一样传递给另一个函数,或者在其他函数内被返回。
高阶函数是将函数用作参数或返回值的函数。例如函数式风格的fold。
lambda表达式是函数字面值,即未声明的函数,但立即作为表达式传递。lambda表达式总是括在花括号中,完整语法形式的参数声明放在花括号内,函数体跟在一个->符号之后,如果推断出的该lambda的返回类型不是Unit,那么该lambda主体中的最后一个表达式会视为返回值。🌰
max(strings, { a, b -> a.length < b.length })
其中max为高阶函数,它的第二个参数是一个lambda表达式。
在Kotlin中有一个约定:如果函数的最后一个参数是函数,那么作为响应参数传入的lambda表达式可以放在圆括号之外。下图🌰 中两个函数是一样的,第一个就把lambda函数放在圆括号之外了👇
另外,一个lambda表达式只有一个参数是很常见的。如果编译器自己可以识别出签名,也可以不用声明唯一的参数并忽略->。该参数会隐式声明为it 🌰 :
ints.filter { it > 0 } // 这个字面值是 (it: Int) -> Boolean 类型的
内联函数
有时使用内联函数可以为高阶函数提供灵活的控制流。
内联函数是C++的增强特性之一,用来降低程序的运行时间。当内联函数收到编译器的指示时,即可发生内联:编译器将使用函数的定义体来替代函数调用语句,这种替代行为发生在编译阶段而非程序运行阶段
🌰 :
例子来源:白话kotlin:内联函数助你提升运行效率尾递归函数
概念补充
静态类型语言(Statically Typed Language):
编译器间做检查数据类型的语言,即写程序时要声明所有变量的数据类型,是固定的。使用数据之前,必须声明数据类型(int, float, double等)。相当于使用之前,首先要为它们分配好内存空间。
例如:C/C++是静态类型语言的典型代表,其他的静态类型语言有Kotlin, Java, C#等
优点:结构非常规范,便于调试,方便类型安全
缺点:为此需要写更多类型相关的代码,不便于阅读,不清晰明了
动态类型语言(Dynamically Typed Language):
运行期间才做数据类型检查的语言,即动态类型语言编程时,永远不用给任何变量指定数据类型。该语言会在第一次赋值给变量时,在内部将数据类型记录下来。
例如:JavaScript, Ruby, Python, php
以上概念参考编程语言傻傻分不清:弱类型、强类型、动态类型、静态类型
函数字面值(量)
函数字面值(量) 即一段函数文本,说白了就是一段代码,可以当作参数来传递。 在Kotlin 中, Lambda 表达式 、 匿名函数 ,都是一种函数字面值。英文是function literal
.
在Kotlin中,lambda函数,和匿名函数属于函数字面值。