Kotlin Tutorial(10)函式 by Michael | CodeData
top

Kotlin Tutorial(10)函式

分享:

Kotlin Tutorial(9)物件與null << 前情

在物件導向程式設計一個主要的特性是封裝(Encapsulation),基礎的工作是把一組資料與功能包裝在一個類別。功能的部份在Kotlin稱為「函式、function」,對Java來說是類別中的「方法、method」。瞭解函式的設計與應用,是學習物件導向技術一個很重要的部份。

宣告與呼叫函式

設計應用程式的時候,通常會有一些經常需要執行的工作,這些執行工作的程式碼,會在不同的地方執行,所以應該要宣告一個函式包裝這些程式碼。下面是Kotlin宣告函式的語法:

fun 函式名稱(參數名稱:參數型態,...): 回傳值型態 {
    ...
    return ...
}

Kotlin的函式不一定要宣告在某個類別裡面,宣告函式的時候,依照提供的功能決定每一個函式下列三個部份:

  • 名稱:根據功能自己取一個函式名稱
  • 參數:執行函式的功能,需要由呼叫的地方提供資料才可以正常運作
  • 回傳值型態:執行函式的功能以後,函式回傳結果的資料型態

例如下面這個呼叫後會在畫面上顯示訊息的函式,執行的工作非常簡單,所以不需要參數與回傳值:

// 宣告沒有參數、沒有回傳值的函式
fun hello(): Unit {
    println("Hello! Kotlin!")
}

// 宣告沒有回傳值的函式,可以省略「:Unit」
fun hello01() {
    println("Hello! Kotlin!")
}

fun main(args: Array<String>) {
    hello()
    // 顯示: Hello! Kotlin!

    hello01()
    // 顯示: Hello! Kotlin!        
}

如果函式在執行後需要回傳資料,必須宣告回傳資料的型態,在函式裡面的程式碼,使用「return」回傳資料:

// 宣告沒有參數、回傳值為String的函式
fun getGreeting(): String {
    return "Hello! Kotlin!"
}

fun main(args: Array<String>) {
    println( getGreeting() )
    // 顯示: Hello! Kotlin!            

    val greet = getGreeting()
    println(greet)
    // 顯示: Hello! Kotlin!
}

單一運算式函式

如果一個函式執行的工作比較簡單一些,只有一行回傳結果的敘述,也就是return敘述,可以使用下面的單一運算式函式(Single-Expression functions)的宣告語法:

fun 函式名稱(參數名稱:參數型態=預設值,...) = 運算式

下面的程式片段示範單一運算式函式的宣告與使用:

// 如果函式的程式碼只有一行return敘述
// 可以使用單一運算式函式(Single-Expression functions)的寫法
fun getHello01(): String = "Hello! Kotlin!"

// 單一運算式函式可以省略函式回傳值型態的宣告
fun getHello02() = "Hello! Kotlin!"    

fun main(args: Array<String>) {
    println( getHello01() )
    // 顯示: Hello! Kotlin!

    println( getHello02() )
    // 顯示: Hello! Kotlin!
}

參數

根據函式的工作需求,可能需要在呼叫的時候,提供資料給函式使用,這些資料通常稱為參數(Parameters)。如果函式需要參數的宣告,在函式名稱後面的左右括號裡面,定義參數的名稱與資料型態,如果需要一個以上的參數,每一個參數之間使用逗號(,)隔開。

下面的程式片段示範參數的宣告與使用:

// 宣告接收一個String參數、沒有回傳值的函式
fun sayHello(name: String) {
    println("Hello! $name!")
}

// 宣告接收三個參數、沒有回傳值的函式
fun person01(name: String, age: Int, married: Boolean) {
    println("Name: $name, Age: $age, Married: ${if (married) "Yes" else "No"}")
}

fun main(args: Array<String>) {
    // 依照函式參數的定義,在呼叫的時候提供一個字串資料給函式使用
    sayHello("Simon")
    // 顯示: Hello! Simon!

    // 呼叫的時候,依照函式參數的宣告,依序提供資料給函式使用
    person01("Simon", 35, true)
    // 顯示: Name: Simon, Age: 35, Married: Yes
}

函式多載

在設計應用程式時候,有時候會宣告下面這樣的函式:

// 接收兩個整數參數,傳回比較大的數字
fun maxInt(x: Int, y: Int) = if (x > y) x else y

// 接收兩個小數參數,傳回比較大的數字
fun maxDouble(x: Double, y: Double) = if (x > y) x else y

上面的範例為兩個函式依照執行的工作,定義名稱為maxInt與maxDouble,雖然這樣的作法,在使用上很清楚而且沒有問題,不過因為執行的工作同樣為接收兩個參數再傳回比較大的數字,只是參數的型態不一樣而已。這類的函式可以為它們定義同樣的名稱,使用不同的參數個數或型態來區分就可以了。

下面的程式片段示範函式多載的宣告與使用:

// 接收兩個整數參數,傳回比較大的數字
fun max(x: Int, y: Int) = if (x > y) x else y
// 接收兩個小數參數,傳回比較大的數字
fun max(x: Double, y: Double) = if (x > y) x else y

fun main(args: Array<String>) {
    // 呼叫函式的時候提供兩個整數,所以會呼叫兩個Int參數的函式
    println("max(3, 5) = ${max(3, 5)}")
    // 顯示: max(3, 5) = 5

    // 呼叫函式的時候提供兩個小數,所以會呼叫兩個Double參數的函式        
    println("max(3.2, 5.6) = ${max(3.2, 5.6)}")
    // 顯示: max(3.2, 5.6) = 5.6
    println()    
}

參數預設值

使用函式多載可以簡化函式的宣告,也可以使用同樣的名稱呼叫不同的函式,不過每一個不同的參數需求,都需要宣告一個函式。例如下面的範例程式,根據呼叫函式提供的資料,決定個人資訊的預設值:

// 接收姓名、年齡與是否結婚參數並顯示資訊
fun person02(name: String, age: Int, married: Boolean) {
    println("Name: $name, Age: $age, Married: ${if (married) "Yes" else "No"}")
}

// 接收姓名與年齡參數,是否結婚預設為否
fun person02(name: String, age: Int) {
    println("Name: $name, Age: $age, Married: No")
}

// 接收姓名參數,年齡預設為0,是否結婚預設為否
fun person02(name: String) {
    println("Name: $name, Age: 0, Married: No")
}

上面範例程式的需求,可以使用Kotlin提供的參數預設值簡化函式的宣告:

fun 函式名稱(參數名稱:參數型態=預設值,...) {
    ...
}

下面的程式片段示範參數預設值的宣告與使用:

// 在參數宣告後面設定參數的預設值
fun person03(name: String, age: Int = 0, married: Boolean = false) {
    println("Name: $name, Age: $age, Married: ${if (married) "Yes" else "No"}")
}

fun main(args: Array<String>) {
    // 呼叫函式的時候,可以省略設定預設值的參數
    person03("Mary")
    // 顯示: Name: Mary, Age: 0, Married: No
    // age與married使用參數設定的預設值

    person03("Mary", 3)
    // 顯示: Name: Mary, Age: 3, Married: No
    // married使用參數設定的預設值

    person03("Mary", 32, true)
    // 顯示: Name: Mary, Age: 32, Married: Yes
}

參數名稱

如果一個函式有比較多的參數宣告,呼叫的時候,一定要依照參數宣告的順序,提供資料給函式使用。Kotlin提供下面呼叫函式的語法,可以在呼叫函式的時候,依照自己的需求提供參數資料:

函式名稱(參數名稱=參數值,...)

下面的程式片段示範在提供參數的時候,使用參數名稱指定參數資料的作法:

fun person03(name: String, age: Int = 0, married: Boolean = false) {
    println("Name: $name, Age: $age, Married: ${if (married) "Yes" else "No"}")
}

fun main(args: Array<String>) {
    // 呼叫函式的時候,可以使用參數名稱設定傳遞的值
    // 就不用依照函式宣告參數的順序傳遞
    person03("John", married = true, age = 24)
    // 顯示: Name: John, Age: 24, Married: Yes

    person03("John", married = true)
    // 顯示: Name: John, Age: 0, Married: Yes
}

變動個數參數

有時候函式多載的設計方式,很不適合下面範例程式的需求:

fun averageOverload(a: Int, b: Int) = (a + b) / 2
fun averageOverload(a: Int, b: Int, c: Int) = (a + b + c) / 3
fun averageOverload(a: Int, b: Int, c: Int, d: Int) = (a + b + c + d) / 4

為了提供計算多個整數平均值的功能,使用上面範例程式的設計方式,需要宣告非常多的函式,而且有一種永遠寫不完的感覺,例如計算32個整數平均值的函式。

這類的應用可以使用Kotlin的變動個數參數的宣告,在參數的前面加上「vararg」,可以讓這個參數接收指定型態0到多個資料:

vararg 參數名稱:參數型態

下面的程式片段示範變動個數參數的宣告與使用:

// 使用vararg設定參數可以接收零到多個值
// 呼叫這個函式可以在傳遞零到多個整數
// 參數的資料型態為陣列
fun average(vararg ns: Int): Int {
    var total = 0

    // 使用迴圈處理陣列的所有元素(合計)
    for (n in ns) {
        total += n
    }

    // 傳回平均值
    return total / ns.size
}

fun main(args: Array<String>) {
    println( average(1, 2, 3) )

    println( average(1, 2, 3, 4, 5, 6) )
}    

在函式中使用變動個數參數,要遵守下面的規定:

  • 一個函式只能有一個設定為vararg的參數
  • 如果除了vararg參數外還有其它參數,vararg參數必須宣告在所有參數的最後一個

下面的程式片段示範變動個數參數的宣告與使用:

// 編譯錯誤,一個函式只能有一個設定為vararg的參數
//fun average02(vararg ns: Int, vararg ns2: Int) {
//    return 0
//}

// 除了vararg參數外還有其它參數,可是宣告在vararg參數後面
// 雖然這樣的宣告不會發生編譯錯誤...
fun average03(vararg ns: Int, message: String) {
    var total = 0

    // 使用迴圈處理陣列的所有元素(合計)
    for (n in ns) {
        total += n
    }

    val average = total / ns.size

    println("$message: $average")
}

// 除了vararg參數外還有其它參數
// vararg參數必須宣告在所有參數的最後一個
fun average04(message: String, vararg ns: Int) {
    var total = 0

    // 使用迴圈處理陣列的所有元素(合計)
    for (n in ns) {
        total += n
    }

    val average = total / ns.size

    println("$message: $average")
}

fun main(args: Array<String>) {
    // 在呼叫的時候發生編譯錯誤
    //println(average03(1,2,3, "Average"))

    average04("Average", 1,2,3)
}

下一步

瞭解函式的設計以後,接下來準備為應用程式加入類別,認識物件的建立與使用。

相關的檔案都可以在GitHub瀏覽與下載。

https://github.com/macdidi5/Kotlin-Tutorial

後續 >> Kotlin Tutorial(11)類別與物件

分享:
按讚!加入 CodeData Facebook 粉絲群

相關文章

留言

留言請先。還沒帳號註冊也可以使用FacebookGoogle+登錄留言