練習問題: Kotlin の基本

1. 始める前に

Kotlin プログラミングの基本を身につけたところで、今度は実践してみましょう。

この演習では、学習したコンセプトの理解度をテストします。実際のユースケースをテーマとしており、一部は以前に経験したことがあるかもしれません。

手順に沿って、各問題の解答を考えましょう。練習問題によっては、行き詰まった場合に役立つヒントが用意されています。解答コードは最後に掲載されていますが、演習に取り組んでから解答を確認することを強くおすすめします。

解答は問題を解決する方法の一つと捉え、自信を持って自由に試しましょう。一部の演習は複数の方法で解くことができます。また、関数と変数に異なる名前を使用できます。

自分のやりやすいペースで問題に取り組みましょう。時間が記載されていますが、これはあくまでも目安であり、遵守する必要はありません。必要なだけ時間をかけ、じっくりと問題に取り組んでください。

Kotlin のプレイグラウンドを使用して演習に取り組むことをおすすめします。

前提条件

必要なもの

  • ウェブブラウザがインストールされた、インターネットに接続できるパソコン

2. メッセージを出力する

このパスウェイで学習した内容を友人に伝えましょう。

  • 次のようにメッセージを 4 行に分けて出力する 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 つの文字列に + 演算子を使用するとどうなりますか。

ステップ 2

このコードは機能して出力を生成しますが、出力にパーティー出席者の合計人数は表示されません。

  • コードの問題点を見つけて、次の出力を行うように修正できますか。
The total party size is: 50

6. メッセージの書式設定

このプログラムは、ある従業員が今月受け取る給与の総額を表示します。給与の総額は、ある従業員が毎月受け取る額の baseSalary 変数と、その従業員に追加で支給されるボーナスの bonusAmount 変数という、2 つの部分に分かれています。

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() 関数ではコンパイル エラーが 1 つ発生します。

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

    println("$firstNumber + $secondNumber = $result")
}
  • プログラムが次の出力を表示するようにエラーを修正できますか。
10 + 5 = 15

ステップ 2

このコードは機能しますが、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

これで、2 つの数を加算する再利用可能な関数ができました。

  • add() 関数を実装したときと同様に subtract() 関数を実装できますか。subtract() 関数を使用するように main() 関数も変更し、想定どおりに動作することを確認します。

ヒント: 加算、減算、その他の数学演算の違いを考えてください。そこから解答コードに取り組みましょう。

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. 2 つの数を比較する

最新のスマートフォンには、利用時間(1 日にスマートフォンに費やした時間)を記録する機能が組み込まれています。

この演習では、今日スマートフォンに費やした時間(分単位)と昨日費やした時間を比較する関数を実装します。この関数は 2 つの整数パラメータを受け入れ、ブール値を返します。

最初のパラメータは今日費やした時間(分単位)、2 番目のパラメータは昨日費やした時間(分単位)です。この関数は、昨日より今日の方がスマートフォンに費やした時間が多い場合に 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 つ忘れたりするかもしれません。

  1. main() 関数の繰り返しを減らすために、1 つの都市について天気の詳細情報を表示する関数を作成し、残りの都市についても同様にできますか。
  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.")
}

コンパイル エラーを修正する

コードにはコンパイル エラーが 2 つ含まれていました。

  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

numberOfAdults 変数と numberOfKids 変数を囲んでいる二重引用符を削除して Int 変数に変換します。

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

Kotlin コンパイラは代入された値に基づいて変数の型を推定できる、ということを覚えているでしょうか。この場合、コンパイラは numberOfAdults 変数と numberOfKids 変数が 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. firstNumber パラメータと secondNumber パラメータ(どちらも Int 型)を受け取り Int 値を返す add() 関数を作成します。
  2. add() 関数の本文に加算演算のコードを入力し、return キーワードを使用して演算の結果を返します。
fun add(firstNumber: Int, secondNumber: Int): Int {
    return firstNumber + secondNumber
}

ステップ 3

  1. firstNumber パラメータと secondNumber パラメータ(どちらも Int 型)を受け取り Int 値を返す subtract() 関数を定義します。
  2. subtract() 関数の本文に減算演算のコードを入力し、return キーワードを使用して演算の結果を返します。
fun subtract(firstNumber: Int, secondNumber: Int): Int {
    return firstNumber - secondNumber
}
  1. 新しい subtract() 関数を使用するように main() 関数を変更します。解答例を以下に示します。
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. operatingSystem パラメータと emailId パラメータ(どちらも String 型)を受け取り String 値を返す displayAlertMessage() 関数を作成します。
  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
}

2 つの数を比較する

  • timeSpentToday パラメータと timeSpentYesterday パラメータ(どちらも Int 型)を受け取り Boolean 値を返す compareTime() 関数を作成します。

解答では > 比較演算子を使用します。この演算子は 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() ステートメントのアンカラ固有の部分を変数に置き換えます。

変数名にはキャメルケースの命名規則を使用し、変数の前に $ 記号を付けて、変数名の代わりに変数の値が使用されるようにしてください。これらは以前の 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. printWeatherForCity() 関数を呼び出してアンカラの天気の詳細情報を渡すように、main() 関数を更新します。

都市名は "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() 関数という 1 か所に集約されています。天気の詳細情報の表示方法を変更する場合は、1 か所で変更してすべての都市に適用できます。

13. その他の演習

Kotlin 言語に関するその他の演習については、JetBrains Academy の Kotlin 基本トラックをご覧ください。特定のトピックに移動するには、ナレッジマップに移動して、このトラックで扱っているトピックの一覧を確認してください。