练习题: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

代码有效,但添加两个数字的逻辑位于 result 变量中,这使得您的代码的可重用性降低。相反,您可以将加法运算提取到一个 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[email protected] 作为 emailId 调用该函数,则它应返回此字符串

There's a new sign-in request on Chrome OS for your Google Account [email protected].

步骤 1

  1. 您能否在此程序中实现 displayAlertMessage() 函数,使其打印显示的输出?
fun main() {
    val operatingSystem = "Chrome OS"
    val emailId = "[email protected]"

    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 [email protected].

步骤 2

干得好!您已显示了消息。但是,在某些情况下,您发现无法确定用户的操作系统。在这种情况下,您需要将操作系统名称指定为 Unknown OS。您可以进一步优化代码,以便不必每次调用函数时都传递 Unknown OS 参数。

  1. 您能否找到一种使用此信息优化代码的方法,使其打印此输出?
There's a new sign-in request on Unknown OS for your Google Account [email protected].

There's a new sign-in request on Windows for your Google Account [email protected]. 

There's a new sign-in request on Mac OS for your Google Account [email protected]. 
  1. 要打印上述消息,请将 main() 函数实现替换为此实现
fun main() {
    val firstUserEmailId = "[email protected]"

    // 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 = "[email protected]"

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

    val thirdUserOperatingSystem = "Mac OS"
    val thirdUserEmailId = "[email protected]"

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