【Kotlin】レッスン3-5:関数のオーバーロードを理解しよう|引数の違いによる関数の使い分け

ながみえ

一つ前のページでは真偽値を返す関数について学習しました。

今回は 関数のオーバーロード について見ていきましょう。

Lesson1:基礎文法編
Lesson2:制御構造編
Lesson3:関数編

 ・Lesson3-1:関数の基本を理解しよう
 ・Lesson3-2:デフォルト引数とキーワード引数を理解しよう
 ・Lesson3-3:関数の戻り値を理解しよう
 ・Lesson3-4:真偽値を返す関数を理解しよう
 ・Lesson3-5:関数のオーバーロードを理解しよう ◁今回はココ
 ・Lesson3-6:ジェネリクスの基礎を理解しよう
 ・確認問題3-☆1:ブラックジャックゲームを作ろう
 ・確認問題3-☆2:丁半賭博ゲームを作ろう
 ・確認問題3-☆3:モンスターとのバトルゲームを作ろう
Lesson4:コレクション編
Lesson5:オブジェクト指向編

<<前のページ

学習記事一覧

次のページ>>

関数オーバーロードとは?|同名関数を引数で使い分ける方法

関数のオーバーロードは、同じ名前の関数を異なる引数の組み合わせで定義できる便利な仕組みです。

Kotlinのプログラムを簡潔かつ効率的にするために役立ちます。

関数のオーバーロードとは何か?|仕組みとコードの例

関数のオーバーロード とは、同じ名前の関数を異なる引数リストで複数定義することです。

例えば文字列を出力する関数と、数値を出力する関数を別々の名前で作成せずに、同じ名前を使いつつ、それぞれ異なる引数を処理できるようにします。

関数のオーバーロードの簡単な使用例を以下の紹介します。

// 同じ名前の関数を3つ定義(関数のオーバーロード)
fun printMessage(message: String) {	// String型の引数messageを持つ
    println("String: $message")
}
fun printMessage(number: Int) {		// Int型の引数numberを持つ
    println("Int: $number")
}
fun printMessage(message: String, count: Int) {	// 2つの引数を持つ
    println("String: $message")
    println("Int: $number")
}

この例ではprintMessageという同じ名前の関数を3種類定義しており、それぞれ引数の型や数が異なります。

メイン関数から呼び出す際には、次のような記述します。

fun main() {
    printMessage("Hello, Kotlin!")	// String型の引数を渡して関数を呼び出し
    printMessage(42)				// Int型の引数を渡して関数を呼び出し
    printMessage("Java", 3)			// 2つの引数を渡して関数を呼び出し
}

このコードを実行すると以下のように出力されます。

String: Hello, Kotlin!
Int: 42
String: Java
Int: 3

このように、引き渡す引数の型や数に基づいて対応する関数が呼び出されます。

これが関数のオーバーロードです。

関数オーバーロードの活用シーン|柔軟なコード設計を可能にする

関数のオーバーロードは、以下のようなシナリオで役立ちます。

  • ユーザーに異なるデータ型を入力させる場合(文字列、数値など)。
  • 同じ処理を複数の条件で実行したい場合。

例えば、簡易な計算関数を考えましょう。

fun add(a: Int, b: Int): Int {			// 整数と整数の加算
    return a + b
}
fun add(a: Double, b: Double): Double {	// 小数と少数の加算
    return a + b
}

2つの数値を計算する場合、それが整数なのか小数なのか判断できない場合があります。

そんな時に、上記のように両方の関数をオーバーロードさせておくことで、気にせず同じ名前で呼び出せるようになります。

オーバーロード使用時のポイントと注意点

Kotlinの関数オーバーロードは、同じ名前の関数でも引数の型や数が異なれば複数定義できる便利な機能です。

しかし、使い方にはいくつかのポイントや注意点があります。

オーバーロードのポイント

  • 関数名は同じ、引数の数や型を変える
    オーバーロードでは関数名は同じですが、引数の型や数が異なるように定義します。
    返り値の型だけを変えてもオーバーロードにはなりません。
  • 引数が重複しないようにする
    引数の型や数が全く同じ関数を複数定義することはできません。
  • 呼び出し時は引数によって自動で選ばれる
    関数を呼び出すとき、渡した引数の型や数に応じて自動的に適切なバージョンが選ばれます。
  • デフォルト引数と併用する際は注意
    デフォルト引数を使ったオーバーロードは、呼び出し方によってはどちらの関数を呼ぶか曖昧になることがあります。
    例:fun foo(a: Int, b: Int = 0)fun foo(a: Int) のような場合は衝突します。

オーバーロードの注意点

  • どちらの関数が呼ばれるか分かりにくい場合がある
    例えばIntLongなど、似た型でオーバーロードした場合、意図しない方が選ばれることがあります。型を明示的に指定するなどの工夫が必要です。
  • コードの可読性が下がることがある
    引数のパターンが多くなりすぎると、どの関数がどんな場面で呼ばれるのか分かりにくくなる場合があります。
    ドキュメントやコメントで意図を補足すると良いでしょう。

まとめ|オーバーロードを活用したスマートな開発へ

この記事では、Kotlinの関数オーバーロードの仕組みや具体的なコード例、利用時のポイントや注意点について解説しました。

オーバーロードを活用すれば、同じ名前の関数でも異なる使い方ができ、より柔軟で分かりやすいコードを書くことができます。

一方で、曖昧な呼び出しや可読性の低下に注意しながら、目的に応じて適切な方法を選択することが大切です。

今回学んだ知識を活かして、より表現力豊かで保守性の高いプログラム作りにチャレンジしてみてください。

オーバーロードの練習問題|異なる引数を処理しよう

同じ名前で複数の関数を定義し、引数に応じて異なる動作をさせる「関数のオーバーロード」を学びましょう。

この練習では複数のオーバーロードされた関数を定義して、それぞれの関数がどのように動作するかを確認します。

具体的には、以下の条件を満たす「挨拶」関数を作成します。

それぞれ異なる引数を渡して、異なる形式の挨拶を画面に出力してください。

この問題の要件

以下の要件に従ってコードを完成させてください。

  1. 基本挨拶: 名前を引数として受け取り、「こんにちは、[名前]さん!」と表示する関数を作成すること。
    • greet("山田") → 出力: こんにちは、山田さん!
  2. 年齢を加えた挨拶: 名前と年齢を引数として受け取り、「こんにちは、[名前]さん!あなたは[年齢]歳ですね。」と表示する関数を作成すること。
    • greet("佐藤", 25) → 出力: こんにちは、佐藤さん!あなたは25歳ですね。
  3. カスタムメッセージの挨拶: 名前とカスタムメッセージを引数として受け取り、「[カスタムメッセージ]、[名前]さん!」と表示する関数を作成すること。
    • greet("田中", "こんにちは") → 出力: こんにちは、田中さん!
  4. 繰り返しの挨拶: 名前、カスタムメッセージ、繰り返し回数を引数として受け取り、指定された回数だけ挨拶を繰り返して表示する関数を作成すること。
  5. メイン関数: 上記のすべての関数を呼び出し、それぞれの動作を確認するコードを記述すること。

ただし、以下のような実行結果となること。

関数のオーバーロードを使った例を示します。
こんにちは、山田 さん!
こんにちは、佐藤 さん!あなたは 25 歳ですね。
こんにちは、田中 さん!
[ 1] おはようございます、鈴木 さん!
[ 2] おはようございます、鈴木 さん!
[ 3] おはようございます、鈴木 さん!

この問題を解くヒント

1からコードを組み立てることが難しい場合は、以下のヒントを開いて参考にしましょう。

Q
ヒント1【コードの構成を見る】

正解のコードは上から順に以下のような構成となっています。
(※下記の□はコード内のインデントを表しています)

1:メイン関数の定義
  □ println関数で「関数のオーバーロードを使った例を示します。」を出力
  □ greet関数を呼び出し、引数として「山田」を渡す
  □ greet関数を呼び出し、引数として「佐藤」と25を渡す
  □ greet関数を呼び出し、引数として「田中」と「こんにちは」を渡す
  □ greet関数を呼び出し、引数として「鈴木」、「おはようございます」、3を渡す
2:greet関数のオーバーロード例1の定義
  □ 引数nameを受け取り、”こんにちは、name さん!”を出力
3:greet関数のオーバーロード例2の定義
  □ 引数nameとageを受け取り、”こんにちは、name さん!あなたは age 歳ですね。”を出力
4:greet関数のオーバーロード例3の定義
  □ 引数nameとmessageを受け取り、”message、name さん!”を出力
5:greet関数のオーバーロード例4の定義
  □ 引数name、message、timesを受け取り、forループでtimes回繰り返す
  □ □ ループの現在の回数と”message、name さん!”を出力

Q
ヒント2【穴埋め問題にする】

以下のコードをコピーし、コメントに従ってコードを完成させて下さい。

// メイン関数の定義
fun main() {
    // 関数のオーバーロードを学ぶ例
    println("関数のオーバーロードを使った例を示します。")

    // 1つ目の関数を呼び出し
    /*
    【穴埋め問題1】ここで名前のみを引数にしてgreet関数を呼び出すコードを書いてください
    */

    // 2つ目の関数を呼び出し(年齢を追加)
    /*
    【穴埋め問題2】ここで名前と年齢を引数にしてgreet関数を呼び出すコードを書いてください
    */

    // 3つ目の関数を呼び出し(名前と挨拶を変更)
    /*
    【穴埋め問題3】ここで名前とカスタムの挨拶を引数にしてgreet関数を呼び出すコードを書いてください
    */

    // 繰り返しを使った挨拶の例
    /*
    【穴埋め問題4】ここで名前、挨拶、回数を引数にしてgreet関数を呼び出すコードを書いてください
    */
}

// greet関数のオーバーロード例1: 名前のみを表示する
fun greet(name: String) {
    /*
    【穴埋め問題5】ここで引数nameを使って挨拶を表示するコードを書いてください
    */
}

// greet関数のオーバーロード例2: 名前と年齢を表示する
fun greet(name: String, age: Int) {
    /*
    【穴埋め問題6】ここで引数nameとageを使って挨拶を表示するコードを書いてください
    */
}

// greet関数のオーバーロード例3: カスタムの挨拶を表示する
fun greet(name: String, message: String) {
    /*
    【穴埋め問題7】ここで引数messageとnameを使って挨拶を表示するコードを書いてください
    */
}

// greet関数のオーバーロード例4: 繰り返しの挨拶を表示する
fun greet(name: String, message: String, times: Int) {
    for (i in 1..times) {
        /*
        【穴埋め問題8】ここでループの現在の回数と引数message、nameを使って挨拶を表示するコードを書いてください
        */
    }
}

このヒントを見てもまだ回答を導き出すのが難しいと感じる場合は、先に正解のコードと解説を見て内容を理解するようにしましょう。

この問題の解答と解説

この問題の正解コードとその解説は以下の通りです。

クリックして開いて確認してください。

Q
正解コード
// メイン関数の定義
fun main() {
    // 関数のオーバーロードを学ぶ例
    println("関数のオーバーロードを使った例を示します。")

    // 1つ目の関数を呼び出し
    greet("山田")
    
    // 2つ目の関数を呼び出し(年齢を追加)
    greet("佐藤", 25)
    
    // 3つ目の関数を呼び出し(名前と挨拶を変更)
    greet("田中", "こんにちは")
    
    // 繰り返しを使った挨拶の例
    greet("鈴木", "おはようございます", 3)
}

// greet関数のオーバーロード例1: 名前のみを表示する
fun greet(name: String) {
    println("こんにちは、$name さん!")
}

// greet関数のオーバーロード例2: 名前と年齢を表示する
fun greet(name: String, age: Int) {
    println("こんにちは、$name さん!あなたは $age 歳ですね。")
}

// greet関数のオーバーロード例3: カスタムの挨拶を表示する
fun greet(name: String, message: String) {
    println("$message、$name さん!")
}

// greet関数のオーバーロード例4: 繰り返しの挨拶を表示する
fun greet(name: String, message: String, times: Int) {
    for (i in 1..times) {
        println("[$i] $message、$name さん!")
    }
}
Q
正解コードの解説

コードをブロックごとに分割して解説します。

メイン関数の開始

fun main() {
    println("関数のオーバーロードを使った例を示します。")
  • fun main():Kotlinのプログラムのエントリーポイントです。
  • println("..."):画面にテキストを出力する関数で、ここではプログラムの開始メッセージを表示しています。

関数の呼び出し

    greet("山田")
    greet("佐藤", 25)
    greet("田中", "こんにちは")
    greet("鈴木", "おはようございます", 3)
  • greet関数の呼び出し:プログラムでは名前やメッセージを渡して、異なる形式の挨拶を表示しています。
  • それぞれの呼び出しで引数の数や型が異なるため、適切なオーバーロードされた関数が呼び出されます。

基本の挨拶

fun greet(name: String) {
    println("こんにちは、$name さん!")
}
  • この関数は1つの引数name(名前)を受け取り、「こんにちは、[名前]さん!」という基本的な挨拶を表示します。
  • $name:文字列テンプレートを使用して変数の値を埋め込んでいます。

年齢を加えた挨拶

fun greet(name: String, age: Int) {
    println("こんにちは、$name さん!あなたは $age 歳ですね。")
}
  • この関数はname(名前)とage(年齢)の2つの引数を受け取ります。
  • メッセージに年齢を追加して、より具体的な挨拶を表示します。

カスタムメッセージの挨拶

fun greet(name: String, message: String) {
    println("$message、$name さん!")
}
  • この関数はname(名前)とmessage(メッセージ)の2つの引数を受け取ります。
  • 挨拶の形式をカスタマイズできるため、ユーザーが好きなメッセージを指定できます。

繰り返しの挨拶

fun greet(name: String, message: String, times: Int) {
    for (i in 1..times) {
        println("[$i] $message、$name さん!")
    }
}
  • この関数はname(名前)、message(メッセージ)、times(繰り返し回数)の3つの引数を受け取ります。
  • for (i in 1..times):指定された回数だけ挨拶を繰り返します。
  • 繰り返し回数を出力の前に表示することで視覚的にわかりやすくしています。
Q
サイト改善アンケート & ご指摘/ご質問

本サイトでは、みなさまの学習をよりサポートできるサービスを目指しております。
そのため、みなさまの「プログラミングを学習する理由」などを アンケート 形式でお伺いしています。

また記事の内容に関する ご指摘ご質問 もお待ちしています。

1.このサイトをどのように活用していますか?また、今後どのように活用したいですか?
5.気になっているサービス・商品があれば教えてください。
※ 特定の記事に関する内容の場合は、記事番号(レッスン〇-〇)をご記入願います。

<<前のページ

学習記事一覧

次のページ>>

記事URLをコピーしました