练习题: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. 字符串模板

此程序通知用户有关特定商品的促销活动。它使用了一个字符串模板,该模板依赖于 discountPercentage 变量表示折扣百分比,并依赖于 item 变量表示促销商品。但是,代码中存在编译错误。

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() 函数中,以便代码可以重用。为此,请使用下面列出的代码更新您的代码。请注意,代码现在引入了一个新的 val 变量 thirdNumber,并打印此新变量与 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 参数,以给定格式构造消息并返回该消息。

例如,如果使用 "Chrome OS" 作为 operatingSystem 参数值,并使用 "sample@gmail.com" 作为 emailId 参数值调用该函数,它应该返回此字符串

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. 创建一个 add() 函数,该函数接受一个 firstNumber 参数和一个 secondNumber 参数,两者都是 Int 类型,并返回一个 Int 值。
  2. add() 函数体内输入加法运算的代码,然后使用 return 关键字返回运算结果。
fun add(firstNumber: Int, secondNumber: Int): Int {
    return firstNumber + secondNumber
}

步骤 3

  1. 定义一个 subtract() 函数,该函数接受一个 firstNumber 参数和一个 secondNumber 参数,两者都是 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. 创建一个 displayAlertMessage() 函数,该函数接受一个 operatingSystem 参数和一个 emailId 参数,两者都是 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
}

比较两个数字

  • 创建一个 compareTime() 函数,该函数接受一个 timeSpentToday 参数和一个 timeSpentYesterday 参数,两者都是 Int 类型,并返回一个 Boolean 值。

解决方案依赖于 > 比较运算符。该运算符求值为一个 Boolean 值,因此 compareTime() 函数只需返回 timeSpentToday > timeSpentYesterday 的结果。

例如,如果您将 300 参数传递给 timeSpentToday 参数,并将 250 参数传递给 timeSpentYesterday 参数,函数体将求值为 300 > 250,这将返回 true 值,因为 300 大于 250。

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() 语句中特定于安卡拉的部分替换为变量。

请记住对变量名使用驼峰命名法约定,并在变量名前使用 $ 符号,以便使用变量的值而不是变量名。这些是您在之前的 Codelab 中了解到的字符串模板。

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 Core 学习路径。要跳转到特定主题,请访问知识图谱,查看该学习路径涵盖的主题列表。