2018年8月22日 星期三

理解 Kotlin 的 function


程式(Function)的資料型態稱為 funtion type, 它用來定義函式輸出入變數的資料型態,它的語法是小括號接箭頭符號 ( ) ->, 小括號裏面是輸入參數(input parameters)的資料型態(type),箭頭右邊是函式輸出值(funtion output 簡稱函數)的資料型態
        ( input_type, ... ) -> output_type

為了簡化常用的 funtion type, 可以利用 typealias 宣告:
        typealias   myFuntionType =  (Int, String, Any) -> Unit

 Unit 是一種資料型態,它沒有傳回值,呼叫函式可以用程式的成員函數  .invoke( ) 來呼叫, kotlin 程式可以省略 invoke, 而直接用小括號( )就可執行運算得到函數值
        var anonymousFuntion: myFuntionType = fun(x,y):Int { return x+y }
        println("function value is: "+anonymousFuntion(3,5) )
        
上面的關鍵字 fun 就是用來定義函式, 小括號 ( ) 用來定義輸入參數,用冒號 : 定義資料型態, 小括號後面的冒號是定義函式的輸出資料型態,而上述不帶名稱的 fun 定義稱之為匿名函式(anonymous function),Kotlin允許將函式定義在函式內,稱之為區域函式(local function).定義帶名稱區域函式可以像這樣寫:
    fun main(args: Array < String > ) {
        fun myFunction(a: Int, b: Int):Int  {         return a+b              }
        println("function value is:"+myFunction(3,5) )
     }
Kotlin 有一種特殊型態的函式稱為 lambda (希臘字母 λ),它用含箭頭的大括號 {  ->  } 區塊敘述直接編寫程式邏輯並回傳函數值,箭頭左邊是輸入參數, 箭頭右邊是程式邏輯,最後一行的運算值當成函數回傳值,所有的 kotlin 物件都有資料型態,而 lambda 的資料型態就是 function type,因此宣告 lambda 函式   λ(x)=x+3 可以這樣寫:
       var  λ: (Int)->Int = { x -> x+3 }

多數的 lambda 函式可以推導輸出變數的資料型態,因此可以省略 function type 的宣告,而將輸入變數放在函式區塊裡面宣告,因此上式可以簡化為:
       var  λ = { x:Int -> x+3 }

如果 lambda 沒有輸入變數時,也就無需宣告資料型態,因此可以再省略箭頭符號,只剩區塊敘述 { },而最後一條敘述就是回傳值:
       var λ = { println("Hello λ") ; 3}
       println( λ( ) )

當函式的輸入參數包含有另外一個函式時,該函式稱為高階函式(high order function),Kotlin 的高階函數有個特異功能是:當最後一個參數如果是 lambda 函式時,可以將 lambda 函式區塊與參數分離,把它放在高階函式的小括號( )後面,而且當參數是以 lambda 函式為唯一參數時,甚至可以將小括號( )省略不寫,另外當傳進 lambda 函式前面的參數不使用的話,可以用底線 _ 將以上的參數加以省略,例如:

      typealias   λType =  (String, Int, Int) -> Int  // 自定的 function type 別名
      fun main(args: Array) {
          fun λp(λ: λType){            // 定義高階區域函式
                println( λ("hello",3,5) )  // 先呼叫
函式,再列出函數值
          }
         λp { z,x,y -> println(z+":$x+$y="); x+y }  //  λp(x,y) = x+y
         λp { _,x,y -> println("Hi:$x*$y="); x*y }   //  λp(x,y) = x*y
      }


當輸入兩個函式後組合成另一個函式回傳的高階函式稱之為複合函式(compose function)
當 lambda 輸入參數只有一個時, 可以利用  it 當成輸入參數,無需用箭頭符號宣告參數, 並且呼叫成員函數時也可以省略小括號 ( ), lambda 就只留下區塊敘述 { }

       typealias    int2bool = (Int) -> Boolean
       typealias    str2int     = (String) -> Int
       typealias    str2bool = (String) -> Boolean
       fun composeBy( f: int2bool, g: str2int ): str2bool {  // high order compose function
              return { x -> f(g(x)) }    // return the lambda
              // only one parameter , so we can skip -> and use it
             //  return {  f(g(it))  }
       }

       fun main(args: Array <String>) {
              var f: int2bool = { x -> (x%2)==1 }     // fiter if  odd number
              var g: str2int    = { s -> s.length  }      // get the string length
              val strings = listOf("1", "22", "333","4444","5555")

              // strings.filter (  composeBy(f,g)  )   // call  the compose function
               strings.filter { f(g(it)) }    // use  lambda function block              
              .also { println(it) }                     
        }




沒有留言: