练习题:Kotlin 基础知识

1. 准备工作

您已经花了很多精力学习 Kotlin 编程的基础知识,现在是时候将所学知识付诸实践了。

这里的练习可以测试您对所学概念的理解程度,都是以实际用例为主题,其中有些用例您可能之前就遇到过。

请按照说明找出每个问题的解决方案。如果您遇到困难,有些练习还会给出提示来帮助您。解决方案代码就在文末,不过强烈建议您先做练习,然后再看答案。

不妨将提供的解决方案视为解题的方法之一,放心大胆地尝试其他方法。有些练习可以用多种方法来解答,函数和变量也可以使用不同的名称。

您可以按照自己的节奏来解决问题。列出的时长只是一个估算时间,仅供参考。希望您能尽力而为,认真解决每一个问题。

建议使用 Kotlin 园地来解答这些练习。

前提条件

所需条件

  • 可连接到互联网的计算机和网络浏览器

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 园地运行代码,然后查看编译错误。

修正错误后,该程序应能顺利编译,而不会出现任何错误,并且会输出以下内容:

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 园地中运行代码之前,您能确定这个程序的输出吗?

提示:您可以为只读变量重新赋值吗?

修正错误后,该程序应能顺利编译,而不会出现任何错误,并且会输出以下内容:

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 园地中运行代码之前,您能确定这个程序的输出吗?

确定输出后,请在 Kotlin 园地中运行代码,然后检查您的输出是否与显示的输出一致。

提示:如果对两个字符串使用 + 运算符,会出现什么情况?

第 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 园地中运行此代码之前,您能弄清楚它的输出吗?
  2. 如果您在 Kotlin 园地中运行该代码,它会输出您预期的内容吗?

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 形参,并会以给定格式构建消息,然后返回该消息。

例如,如果在调用函数时,用“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 步

  • operatingSystem 形参赋予一个 "Unknown OS" 值。
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,因为 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() 函数后,创建一个会输出 Ankara(安卡拉)这个城市天气详情的函数。

您可以使用 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 基础知识课程。如需跳转到特定主题,请前往知识图谱,查看上述课程涵盖的主题列表。