練習題:Kotlin 基本概念

1. 事前準備

您已花了很多心力瞭解 Kotlin 程式設計的基本知識,現在是時候來實際運用所學了。

這些練習可測試您對於所學概念的理解程度。主題是根據實際用途而定,其中有些您或許已經看過。

按照操作說明找出每個問題的解決方案。如果遇到困難,其中一些練習可以給予提示。雖然解決方案程式碼就在這個練習的結尾處,但我們極力建議您先解決練習中的問題,再查看答案。

不妨將解決方案視為一種解決問題的方法,您也可以盡情地進行實驗。您可以運用多種方式來解決某些練習,並為函式和變數使用不同的名稱。

請依照自己的步調逐一瞭解問題所在。我們提供的預估時間僅供參考,您不必一定要在時間內完成。建議您花些時間仔細思考每個問題的解決方法。

建議使用 Kotlin Playground 來解決這些練習的問題。

必要條件

軟硬體需求

  • 一台可連上網際網路並具備網路瀏覽器的電腦

2. 輸出訊息

和朋友分享在這個課程中學到的知識。

  • 您是否能撰寫可分別以四行輸出這些訊息的 main() 函式?
Use the val keyword when the value doesn't change.
Use the var keyword when the value can change.
When you define a function, you define the parameters that can be passed to it.
When you call a function, you pass arguments for the parameters.

3. 修正編譯錯誤

這個程式會輸出訊息,通知使用者已收到朋友傳送的即時通訊訊息。

fun main() {
    println("New chat message from a friend'}
}
  1. 您能找出這個程式中編譯錯誤的根本原因並加以修正嗎?
  2. 程式碼是否使用適當符號,來表示字串和函式引數的開始和結束?

提示:您可以使用 Kotlin Playground 執行程式碼,並查看編譯錯誤。

修正錯誤後,程式應該可以在沒有錯誤的情況下編譯,且可以將以下內容輸出:

New chat message from a friend

4. 字串範本

這個程式會通知使用者特定商品即將推出的促銷活動。其中包含字串範本,這個範本分別使用 discountPercentageitem 變數來表示折扣百分比和特價商品,但程式碼中含有編譯錯誤。

fun main() {
    val discountPercentage: Int = 0
    val offer: String = ""
    val item = "Google Chromecast"
    discountPercentage = 20
    offer = "Sale - Up to $discountPercentage% discount on $item! Hurry up!"

    println(offer)
}
  1. 您能找出錯誤的根本原因並加以修正嗎?
  2. 在 Kotlin Playground 中執行程式碼前,您能否決定這個程式的輸出內容?

提示:您能否將值重新指派給唯讀變數?

修正錯誤後,程式應該可以在沒有錯誤的情況下編譯,且可以將以下內容輸出:

Sale - Up to 20% discount on Google Chromecast! Hurry up!

5. 字串串連

這個程式會顯示派對總人數。派對中有成人和兒童。numberOfAdults 變數代表派對的成人人數,numberOfKids 變數則代表兒童人數。

fun main() {
    val numberOfAdults = "20"
    val numberOfKids = "30"
    val total = numberOfAdults + numberOfKids
    println("The total party size is: $total")
}

步驟 1

  • 在 Kotlin Playground 中執行程式碼前,您能否決定這個程式的輸出內容?

決定輸出內容之後,請在 Kotlin Playground 中執行程式碼,然後檢查輸出內容是否與所顯示的相符。

提示:在兩個字串中使用 + 運算子會有什麼影響?

步驟 2

程式碼可以執行及輸出部分內容,但輸出內容不會顯示參加派對的總人數。

  • 您是否能找出程式碼中的問題並加以修正,使程式碼可以輸出此內容?
The total party size is: 50

6. 訊息格式

這個程式會顯示員工本月獲得的總薪酬。總薪酬可分為兩個部分:baseSalary 變數 (員工每月收到的薪酬) 和 bonusAmount 變數 (員工可獲得的額外獎勵)。

fun main() {
    val baseSalary = 5000
    val bonusAmount = 1000
    val totalSalary = "$baseSalary + $bonusAmount"
    println("Congratulations for your bonus! You will receive a total of $totalSalary (additional bonus).")
}
  1. 您是否能在 Kotlin Playground 中執行程式碼前,釐清這個程式碼的輸出內容?
  2. 在 Kotlin Playground 中執行程式碼時,程式碼是否如預期輸出內容?

7. 實作基本數學運算

在本練習中,您會編寫一個程式來執行基本數學運算並將內容輸出。

步驟 1

這個 main() 函式有一個編譯錯誤:

fun main() {
    val firstNumber = 10
    val secondNumber = 5

    println("$firstNumber + $secondNumber = $result")
}
  • 您能否修正錯誤,讓程式輸出這個內容?
10 + 5 = 15

步驟 2

程式碼雖然正常運作,但新增兩個數字的邏輯位於結果變數中,因而使得程式碼較無法靈活重複使用。您可以改為將加總運算擷取至 add() 函式中,如此一來就能重複使用該程式碼。如要執行這項操作,請使用下列程式碼來更新程式碼。請注意,程式碼現在會實作名為 thirdNumber 的新 val,並以 firstNumber 輸出這個新變數的結果。

fun main() {
    val firstNumber = 10
    val secondNumber = 5
    val thirdNumber = 8

    val result = add(firstNumber, secondNumber)
    val anotherResult = add(firstNumber, thirdNumber)

    println("$firstNumber + $secondNumber = $result")
    println("$firstNumber + $thirdNumber = $anotherResult")
}

// Define add() function below this line
  • 您是否能定義 add() 函式,讓程式能將此內容輸出?
10 + 5 = 15
10 + 8 = 18

步驟 3

現在,您擁有可重複使用的函式可新增兩個數字。

  • 您是否能以實作 add() 函式的方式實作 subtract() 函式?請一併修改 main() 函式來使用 subtract() 函式,這樣您就能確認這個函式是否可正常運作。

提示:請考量加減和其他數學運算之間的差異。開始在這裡運用解決方案程式碼。

8. 預設參數

Gmail 提供一項功能,可於每次有人嘗試在新裝置上登入時,傳送通知給使用者。

在本練習中,您會撰寫一個程式,透過這個訊息範本向使用者顯示訊息:

There's a new sign-in request on operatingSystem for your Google Account emailId.

您必須實作接受 operatingSystem 參數和 emailId 參數的函式,以特定格式建構訊息,然後傳回訊息。

例如,如果為 operatingSystem 使用「Chrome OS」呼叫函式,並為 emailId 使用「sample@gmail.com」呼叫,系統應該會傳回下列字串:

There's a new sign-in request on Chrome OS for your Google Account sample@gmail.com.

步驟 1

  1. 您是否能在這個程式中實作 displayAlertMessage() 函式,藉此輸出顯示的內容?
fun main() {
    val operatingSystem = "Chrome OS"
    val emailId = "sample@gmail.com"

    println(displayAlertMessage(operatingSystem, emailId))
}

// Define your displayAlertMessage() below this line.
  1. 程式是否會輸出這個內容?
There's a new sign-in request on Chrome OS for your Google Account sample@gmail.com.

步驟 2

做得好!您已顯示了這個訊息。然而在某些情況下,您可能會發現自己無法判定使用者的作業系統。此時,必須將作業系統名稱指定為 Unknown OS。您可以進一步將程式碼最佳化,這樣就不需要每次在呼叫函式時傳遞 Unknown OS 引數。

  1. 您是否能找到方法運用這項資訊將程式碼最佳化,以便輸出這項內容?
There's a new sign-in request on Unknown OS for your Google Account user_one@gmail.com.

There's a new sign-in request on Windows for your Google Account user_two@gmail.com.

There's a new sign-in request on Mac OS for your Google Account user_three@gmail.com.
  1. 如要輸出上述訊息,請使用下列項目取代 main() 函式實作:
fun main() {
    val firstUserEmailId = "user_one@gmail.com"

    // The following line of code assumes that you named your parameter as emailId.
    // If you named it differently, feel free to update the name.
    println(displayAlertMessage(emailId = firstUserEmailId))
    println()

    val secondUserOperatingSystem = "Windows"
    val secondUserEmailId = "user_two@gmail.com"

    println(displayAlertMessage(secondUserOperatingSystem, secondUserEmailId))
    println()

    val thirdUserOperatingSystem = "Mac OS"
    val thirdUserEmailId = "user_three@gmail.com"

    println(displayAlertMessage(thirdUserOperatingSystem, thirdUserEmailId))
    println()
}

9. 計步器

計步器是一種可計算步數的電子裝置。如今,幾乎所有手機、智慧型手錶和健身器材都有內建計步器。健康與健身應用程式會使用內建計步器來計算步數。這個函式會根據使用者的步數計算其消耗的卡路里數。

  • 您是否能根據最佳做法,重新命名這個程式中的函式、函式參數和變數?
fun main() {
    val Steps = 4000
    val caloriesBurned = PEDOMETERstepsTOcalories(Steps);
    println("Walking $Steps steps burns $caloriesBurned calories")
}

fun PEDOMETERstepsTOcalories(NumberOFStepS: Int): Double {
    val CaloriesBURNEDforEachStep = 0.04
    val TotalCALORIESburned = NumberOFStepS * CaloriesBURNEDforEachStep
    return TotalCALORIESburned
}

10. 比較兩個數字

現代手機內建一項功能,可追蹤裝置使用時間或每日手機使用時間。

在這項練習中,您會實作一個函式,以分鐘來比較自己今天和昨天使用手機的時間。這個函式接受兩個整數參數,並傳回布林值。

第一個參數會顯示您今天所花費的分鐘數,第二個參數則顯示您昨天所花費的分鐘數。如果與昨天相比,您在手機上花費更多時間,則該函式會傳回 true 值。否則,則會傳回 false 值。

舉例來說,如果使用下列具名引數呼叫函式:

  • timeSpentToday = 300timeSpentYesterday = 250,函式會傳回 true 值。
  • timeSpentToday = 300timeSpentYesterday = 300,函式會傳回 false 值。
  • timeSpentToday = 200timeSpentYesterday = 220,函式會傳回 false 值。

提示:如果運算子之前的值大於之後的值,則 > 比較運算子會傳回 true 值。否則,則會傳回 false 值。

11. 將重複的程式碼移到函式中

這個程式會顯示不同城市的天氣資訊。包括城市名稱、當天的高溫和低溫,以及降雨機率。

fun main() {
    println("City: Ankara")
    println("Low temperature: 27, High temperature: 31")
    println("Chance of rain: 82%")
    println()

    println("City: Tokyo")
    println("Low temperature: 32, High temperature: 36")
    println("Chance of rain: 10%")
    println()

    println("City: Cape Town")
    println("Low temperature: 59, High temperature: 64")
    println("Chance of rain: 2%")
    println()

    println("City: Guatemala City")
    println("Low temperature: 50, High temperature: 55")
    println("Chance of rain: 7%")
    println()
}

程式碼有許多相似之處,可針對每個城市輸出天氣資訊。例如有些詞組會重複出現,像是 "City:""Low temperature:"。同樣地,重複的程式碼也會造成程式出現錯誤的風險。可能其中一個城市有拼寫錯誤,或是您遺漏了其中一筆天氣的詳細資料。

  1. 您是否能建立函式來輸出單一城市的天氣詳細資料,以便減少 main() 函式中的重複情形,並對其餘城市重複上述步驟?
  2. 您是否能更新 main() 函式,來呼叫您為每個城市所建立的函式,並傳遞適當的天氣詳細資料做為引數?

12. 解決方案程式碼

這項解決方案會使用 println() 函式輸出每一行的訊息。

fun main() {
    println("Use the val keyword when the value doesn't change.")
    println("Use the var keyword when the value can change.")
    println("When you define a function, you define the parameters that can be passed to it.")
    println("When you call a function, you pass arguments for the parameters.")
}

修正編譯錯誤

這個程式碼含有兩個編譯錯誤:

  1. 字串結尾應為雙引號,而非單引號。
  2. 函式引數應以括號而非以大括號結尾。
fun main() {
    println("New chat message from a friend")
}

字串範本

編譯錯誤是將 discountPercentageoffer 唯讀變數指派至新值所產生的結果,而系統不允許這項指派作業。

fun main() {
    val discountPercentage = 20
    val item = "Google Chromecast"
    val offer = "Sale  - Up to $discountPercentage% discount off $item! Hurry Up!"

    println(offer)
}

替代的解決方式是使用 var 關鍵字宣告 discountPercentage 整數和 offer 字串。不過在這個程式中,其值是不可變動的,因此可以繼續使用 val 關鍵字。

字串串連

步驟 1

程式會輸出以下內容:

The total party size is: 2030

這是陷阱題。在 String 值上使用 + 運算子時,系統會產生串連字串。由於整數是以雙引號括住,因此系統會將其視為字串,而非整數,因此輸出 2030 的結果。

步驟 2

您可以移除 numberOfAdultsnumberOfKids 變數前後的雙引號,來將其轉換為 Int 變數。

fun main() {
    val numberOfAdults = 20
    val numberOfKids = 30
    val total = numberOfAdults + numberOfKids
    println("The total party size is: $total")
}

假如您記得,Kotlin 編譯器可根據指派的值來推斷變數類型。在這個範例中,編譯器推斷 numberOfAdultsnumberOfKids 變數為 Int 類型。

訊息格式

程式會輸出以下內容:

Congratulations for your bonus! You will receive a total of 5000 + 1000 (additional bonus).

"$baseSalary + $bonusAmount" 使用範本運算式語法。在範本運算式中,系統會先評估程式碼,然後再將結果在字串中串連。

在這個問題中,$baseSalary 變數經評估為 5000 值,而 $bonusAmount 變數經評估為 1000 值。接著,系統會串連結果以產生 "5000 + 1000",並將結果指派給 result 變數。

實作基本數學運算

步驟 1

使用 val 關鍵字定義不可變動的 result 變數,然後為其指派加總運算的結果:

fun main() {
    val firstNumber = 10
    val secondNumber = 5

    val result = firstNumber + secondNumber
    println("$firstNumber + $secondNumber = $result")
}

步驟 2

  1. 建立可接受 firstNumbersecondNumber 參數的 add() 函式,兩者皆為 Int 類型,接著傳回 Int 值。
  2. add() 函式主體中輸入加總運算的程式碼,接著使用 return 關鍵字傳回運算結果。
fun add(firstNumber: Int, secondNumber: Int): Int {
    return firstNumber + secondNumber
}

步驟 3

  1. 定義接受 firstNumbersecondNumber 參數的 subtract() 函式,兩者皆為 Int 類型並傳回 Int 值。
  2. subtract() 函式主體中輸入減法運算的程式碼,接著使用 return 關鍵字傳回運算結果。
fun subtract(firstNumber: Int, secondNumber: Int): Int {
    return firstNumber - secondNumber
}
  1. 修改 main() 函式即可使用新的 subtract() 函式。解決方案範例如下:
fun main() {
    val firstNumber = 10
    val secondNumber = 5
    val thirdNumber = 8

    val result = add(firstNumber, secondNumber)
    val anotherResult = subtract(firstNumber, thirdNumber)

    println("$firstNumber + $secondNumber = $result")
    println("$firstNumber - $thirdNumber = $anotherResult")
}

fun add(firstNumber: Int, secondNumber: Int): Int {
    return firstNumber + secondNumber
}

fun subtract(firstNumber: Int, secondNumber: Int): Int {
    return firstNumber - secondNumber
}

預設參數

步驟 1

  1. 建立可接受 operatingSystememailId 參數的 displayAlertMessage() 函式,兩者皆為 String 類型,接著傳回 String 值。
  2. 在函式主體中,使用範本運算式更新訊息並將其傳回。
fun displayAlertMessage(operatingSystem: String, emailId: String): String {
    return "There is a new sign-in request on $operatingSystem for your Google Account $emailId."
}

步驟 2

  • "Unknown OS" 值指派給 operatingSystem 參數。
fun displayAlertMessage(
    operatingSystem: String = "Unknown OS",
    emailId: String
): String {
    return "There is a new sign-in request on $operatingSystem for your Google Account $emailId."
}

計步器

函式名稱和變數名稱應遵循「駝峰式大小寫」慣例。

如果名稱包含多個字詞,第一個字詞的首字母請使用小寫、其餘字詞的首字母則使用大寫,字詞之間的所有空格也要移除。

範例函式名稱包含:

  • calculateTip
  • displayMessage
  • takePhoto

範例變數名稱包含:

  • numberOfEmails
  • cityName
  • bookPublicationDate

如要進一步瞭解名稱,請參閱命名規則

請避免使用 Kotlin 關鍵字做為函式名稱,因為這些字詞已在 Kotlin 語言中被賦予具體意義。

您的解決方案程式碼看起來應該會類似以下的程式碼片段:

fun main() {
    val steps = 4000
    val caloriesBurned = pedometerStepsToCalories(steps);
    println("Walking $steps steps burns $caloriesBurned calories")
}

fun pedometerStepsToCalories(numberOfSteps: Int): Double {
    val caloriesBurnedForEachStep = 0.04
    val totalCaloriesBurned = numberOfSteps * caloriesBurnedForEachStep
    return totalCaloriesBurned
}

比較兩個數字

  • 建立可接受 timeSpentTodaytimeSpentYesterday 參數的 compareTime() 函式,兩者皆為 Int 類型,接著傳回 Boolean 值。

這項解決方案會使用 > 比較運算子。運算子會評估 Boolean 值,因此 compareTime() 函式只會傳回 timeSpentToday > timeSpentYesterday 的結果。

舉例來說,如果將 300 引數傳遞至 timeSpentToday 參數,並將 250 引數傳遞至 timeSpentYesterday 參數,那麼函式主體會評估 300 > 250,因為 300 大於 250,所以會傳回 true

fun main() {
    println("Have I spent more time using my phone today: ${compareTime(300, 250)}")
    println("Have I spent more time using my phone today: ${compareTime(300, 300)}")
    println("Have I spent more time using my phone today: ${compareTime(200, 220)}")
}

fun compareTime(timeSpentToday: Int, timeSpentYesterday: Int): Boolean {
    return timeSpentToday > timeSpentYesterday
}
Have I spent more time using my phone today: true
Have I spent more time using my phone today: false
Have I spent more time using my phone today: false

將重複的程式碼移到函式中

  1. 建立可在 main() 函式後輸出安卡拉城的天氣詳細資料的函式。

針對函式名稱,您可以使用 printWeatherForCity() 或類似的程式碼。

  1. main() 函式中呼叫該函式。

這個程式應輸出安卡拉的天氣詳細資料。

fun main() {
    printWeatherForCity()
}

fun printWeatherForCity() {
    println("City: Ankara")
    println("Low temperature: 27, High temperature: 31")
    println("Chance of rain: 82%")
    println()
}

您現在可以建立更為彈性的函式,方便輸出其他城市的天氣詳細資料。

  1. println() 陳述式的安卡拉特定部分替代為變數。

記得遵循慣例,在變數之前為變數名稱和 $ 符號使用駝峰式大小寫,這樣系統才會使用變數值而非變數名稱。這些是您在先前的程式碼研究室中學到的字串範本。

fun printWeatherForCity() {
    println("City: $cityName")
    println("Low temperature: $lowTemp, High temperature: $highTemp")
    println("Chance of rain: $chanceOfRain%")
    println()
}
  1. 變更函式定義,讓這些變數成為呼叫時必須傳遞至函式的參數,並為每個參數指定資料類型。

cityName 參數為 String 類型,lowTemphighTempchanceOfRain 參數則為 Int 類型。

由於訊息會輸出至輸出內容,因此函式中不需要使用 return 值。

fun printWeatherForCity(cityName: String, lowTemp: Int, highTemp: Int, chanceOfRain: Int) {
    println("City: $cityName")
    println("Low temperature: $lowTemp, High temperature: $highTemp")
    println("Chance of rain: $chanceOfRain%")
    println()
}
  1. 更新 main() 函式以呼叫 printWeatherForCity() 函式,並傳遞安卡拉的天氣詳細資料。

城市名稱為 "Ankara",低溫為27,高溫為 31,降雨機率為 82

fun main() {
    printWeatherForCity("Ankara", 27, 31, 82)
}

fun printWeatherForCity(cityName: String, lowTemp: Int, highTemp: Int, chanceOfRain: Int) {
    println("City: $cityName")
    println("Low temperature: $lowTemp, High temperature: $highTemp")
    println("Chance of rain: $chanceOfRain%")
    println()
}
  1. 執行程式以確認輸出內容會顯示安卡拉的天氣詳細資料。
  2. 呼叫 printWeatherForCity() 函式,其中含有其他城市的天氣詳細資料。
fun main() {
    printWeatherForCity("Ankara", 27, 31, 82)
    printWeatherForCity("Tokyo", 32, 36, 10)
    printWeatherForCity("Cape Town", 59, 64, 2)
    printWeatherForCity("Guatemala City", 50, 55, 7)
}

fun printWeatherForCity(cityName: String, lowTemp: Int, highTemp: Int, chanceOfRain: Int) {
    println("City: $cityName")
    println("Low temperature: $lowTemp, High temperature: $highTemp")
    println("Chance of rain: $chanceOfRain%")
    println()
}
  1. 執行程式。

雖然輸出內容應該與原先的程式相同,但現在程式碼變得更簡潔,且沒有不必要的重複!用於輸出城市天氣詳細資料的所有程式碼全部集中於一處:printWeatherForCity() 函式。如要變更天氣詳細資料的顯示方式,只要在單一位置進行變更,系統就會套用至所有城市。

13. 其他練習

如果想取得更多有關 Kotlin 語言的練習內容,請查看 JetBrains Academy 的 Kotlin 基本概念課程。如要跳到特定主題,請前往知識地圖,瀏覽課程所涵蓋主題的清單。