函数是执行特定任务的一段代码,程序通过将一段代码定义成函数,并为该函数指定函数名。可在需要的时候多次调用,因此函数是代码复用的重要手段。
定义函数的语法格式:
fun 函数名(形参列表) [:返回值类型]{
//有0条或多条可执行语句
}
-
Kotlin函数声明必须使用fun关键字,函数语法说明如下:
- 函数名:一个合法的标识符,有一个和多个有意义的单词连缀而成。使用驼峰命名法。
- 返回值类型:返回值类型可以是kotlin语言所允许的任何数据类型。如果声明里函数返回值类型,则函数体内应有一条有效的return语句,该语句返回一个变量或一个表达式。如果声明函数没有返回值,则可以省略返回值类型或者使用Unit类型。(Unit相当于java中的void)
- 形参列表:形参列表定义该函数可以接受的函数,形参列表由零组到多组"形参名:参数类型"组合形成,多组参数之间用英文(,)分割。
-
递归函数
在一个函数体内调用它自身,被称为函数递归。函数递归包含了一种隐士的循环。它会重复执行某段代码,单这种重复执行无须循环控制。
当一个函数不断地调用它自身时,必须在某个时刻函数的返回值时确定的,即不再调用它自身;否则递归就变成无穷递归,类似于死循环。因此在定义递归函数时候有一条最重要的规定:递归一定要向已知方向进行。
// f(0) = 1 f(1) = 4 f(n) = 2*f(n-1) + f(n-2) fun fn(n:Int):Int{ if(n == 0) return 1 if(n == 1) return 4 return 2*fn(n-1) + fn(n-2) } fun main(){ var a = fn(0) var b = fn(1) var c = fn(10) var d = fn(2) println(d) println(a) println(b) println(c) }
-
单表达式函数
函数只返回单个表达式时,可以省略花括号并在等号后制定函数体即可。
fun area(x:Double,y:Double):Double = x * y
-
函数参数可以省略形参标示,也可以有写有不写,混合输入时候,顺序不能乱。参数可以使用默认值
-
尾递归函数
当函数将调用自身作为它执行的最后一行代码,且递归调用后没有更多代码时,可使用尾递归语法。使用tailrec标记。
//原方法。计算阶乘 fun faceRect(n:Int):Int{ if(n == 1){ return 1 }else{ return n*faceRect(n-1) } } //尾递归 tailrec fun test(n:Int):Int = if(n == 1) 1 else n*test(n-1) //也可以使用 tailrec fun face(n:Int,total:Int = 1) :Int = if(n == 1) total else face(n -1,total*n)
-
个数可变参数
允许为函数指定数量不确定的形参,形参类型前添加vararg修饰,则表明该形参可接受多个参数值,多个参数值被当成数组传入。kotlin允许个数可变的形参处于形参列表的任意位置,但最多只能带一个个数可变的形参。
fun variableTest(vararg arg:String,num:Int){ for(i in arg.indices) println(arg[i]) println(num) } //variabelTest("a","b","c",num =10)
-
高阶函数
函数本身也具有自己的类型。既可用于定义变量,也可用作函数的形参类型,还可作为函数的返回值类型。
-
使用函数类型
函数类型由函数的形参列表、->、返回值类型组成。如:
fun foo(a:Int, name:String) ->String{
…
}的函数类型是(Int,String)->String。
fun bar(width:Double, height:Double){
...
}的函数类型是(Double,Double) -> Unit或者是(Double,Double)。
//定一个变量是(Int,Int) -> Int类型 var a :(Int,Int) -> Int //定一个变量是(String)类型 var b : (String)
当直接访问一个函数的函数饮用,而不是调用函数时,需要在函数名前添加两个冒号,而且不能在函数后添加括号。一旦添加了就是调用函数。
//定一个变量是(Int,Int) -> Int类型 var a :(Int,Int) -> Int //定一个变量是(String)类型 var b : (String) fun pow(n:Int,m:Int):Int{ return n + m } a = ::pow println(a(1,3)) //4
-
使用函数类型作为形参类型
有时候需要定一个函数,该函数大部分计算逻辑都能确定,但某些处理逻辑暂时无法确定—这意味着某些程序代码需要动态改变,如果希望调用函数时能动态传入这些代码,就需要在函数中定义函数类型的形参,这样即可在调用该函数时传入不通的函数作为参数,从而动态改变这些代码。
fun makeArray(arr:Array<Int>,fn:(Int)->Int): Array<Int>{ var result:Array<Int> = Array(arr.size) {0} for(i in arr.indices){ result[i] = fn(arr[i]) } return result } fun square(int: Int): Int { return int * int } fun div(int: Int) :Int{ return int - 2 } fun cube(num:Int):Int{ return num * num * num } fun main(){ var data = arrayOf(1,2,3,4,5) println(makeArray(data,::square).contentToString()) //[1, 4, 9, 16, 25] println(makeArray(data,::div).contentToString()) //[-1, 0, 1, 2, 3] println(makeArray(data,::cube).contentToString())//[1, 8, 27, 64, 125 }
-
使用函数类型做为返回值
fun main(){ var fn = fnRet("squre") println(fn(6)) //36 } fun fnRet(type:String):(Int) -> Int{ fun squre(n:Int): Int { return n * n } fun cube(n:Int): Int{ return n*n*n } fun factorial(n:Int):Int{ var result = 1 for(index in 2..n){ result *= index } return result } return when(type){ "squre" -> ::squre "cube" -> ::cube else -> ::factorial } }
-
Lambda表达式
{ (形参列表) -> //零条或多条语句 }
- lambda表达式总是被大括号括着
- 定义lambda表达式不需使用fun,不用指定函数名
- 形参列表(如果有的话)在->之前声明,参数类型可以省略
- 函数体(lambda执行体)放在->之后
- 函数最后一行表达式自动被作为Lambda表达式的返回值,无须使用return关键字
fun fnLambda(type:String):(Int)->Int{ when(type){ "squre" -> return { n: Int -> n * n } "cube" -> return { it -> it * it * it } else -> return { it -> var result = 1 for(index in 2..it){ result *= index } result } } }
当lambda表达式形参只有一个参数的时候,可以省略参数名。 如果函数的最后一个参数是函数类型,而且是lambda表达式,那么允许也建议在括号外指定lambda表达式
-