Skip to content

Latest commit

 

History

History
243 lines (179 loc) · 7.22 KB

6函数.md

File metadata and controls

243 lines (179 loc) · 7.22 KB
函数和Lambda表达式

函数是执行特定任务的一段代码,程序通过将一段代码定义成函数,并为该函数指定函数名。可在需要的时候多次调用,因此函数是代码复用的重要手段。

定义函数的语法格式:

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表达式