Caution

お使いのブラウザはJavaScriptが実行できない状態になっております。
当サイトはWebプログラミングの情報サイトの為、
JavaScriptが実行できない環境では正しいコンテンツが提供出来ません。
JavaScriptが実行可能な状態でご閲覧頂くようお願い申し上げます。

  1. トップページ
  2. Swift入門編 - 関数のオーバーロードについて

関数のオーバーロードについて

みなさまどうも。

さて、続きまして関数の『オーバーロード』についてやっていきましょう。『オーバーロード』は日本語でいうと「多重定義」って感じの意味になりますね。

というわけで早速ですが以下のサンプルを見てみて下さい。

func test() {
}

はい、ただ関数『test』を定義しているだけですね。中身も空なので全く意味はありません。

さて、上記のサンプルでさらに全く同じ名前(識別子)の関数『test』を定義してみましょう。こんな感じです。するとエラーになります。

func test() {
}

func test() { // エラーです。
}

こんな感じでSwiftでは同じ名前を持つ関数を複数定義することは基本的にできません。他の言語では上書きする形で再定義できちゃったりするんですがSwiftではNGです。

しかし、最初に定義した関数の引数と、再定義した関数の引数の構成をちょいと変えてみましょう。するとこうなります。

func test() {
}

func test(s: String) { // 定義できます。
}

エラーになってませんね。さらに返り値を変えただけの同じ名前の関数も定義してみましょう。するとこうなります。

func test() {
}

func test(s: String) { // 定義できます。
}

func test() -> String { // 定義できます。
    return "初音ミク"
}

またもや定義できちゃいましたね。

このようにSwiftでは引数または返り値が違う場合は同じ名前(識別子)で複数の関数を定義することができちゃいます。

これが『オーバーロード』と呼ばれる機能になりますね。というわけでこの『オーバーロード』の記述方法から確認していきましょう。

まず引数が違う、というパターンです。以下のサンプルを見て下さい。

func test(a: Int) {
}

func test(a: String) {
}

上記の関数『test』は仮引数名を両方『a』にしてますね。しかしデータ型が違うため同じ名前で複数の関数が定義できています。

ではデータ型を同じにして仮引数名だけ変えてみましょう。こんな感じですね。

func test(a: String) {
}

func test(s: String) {
}

これもOKです。さらに引数の個数のみを変えたパターンをみてみましょう。

func test(s: String) {
}

func test(s: String, _s: String) {
}

これもOKです。というわけで引数に関しては一箇所でも他と違ってれば全部OKってことになります。

続いて返り値が違うパターンです。これも微妙に違ってれば全部OKというイメージで大丈夫です。

func test() -> Int {
    return 1
}

func test() -> String {
    return "初音ミク"
}

ここまでは大丈夫そうでしょうか。続いて関数を実行させる時の動作についてです。

これは同じ名前で定義されている複数の各関数に合わせた引数を与えて実行してあげれば対応する関数を勝手に判定してくれる感じになりますね。

func test(s: String) {
    print("文字列です。")
}

func test(n: Int) {
    print("数値です。")
}

test(s: "あいうえお") // 『文字列です。』が出力されます。

test(n: 1) // 『数値です。』が出力されます。

さて、ここでちょっと注意点です。先程紹介した「返り値だけが違うパターン」を考えてみましょう。以下のやつですね。

func test() -> Int {
    return 1
}

func test() -> String {
    return "初音ミク"
}

上記の複数の関数『test』についてですが、これって全部引数が空ですよね。ってことは関数を実行させるときは全て『test()』って記述することになるので上手く分岐できるはずがなく、なんだかわけわかめです。

ちょっと試してみましょう。こんな感じになります。

func test() -> Int {
    return 1
}

func test() -> String {
    return "初音ミク"
}

test() // エラーです。

はい、エラーになっちゃってますね。

さて、上記の「『オーバーロード』された複数の関数を実行させる場合はどう記述すれば良いのか」という話ですが、これは受け取る変数とか定数とかにデータ型を指定してあげることで上手く分岐してくれるようになります。こんな感じですね。

func test() -> Int {
    return 1
}

func test() -> String {
    return "初音ミク"
}

// 以下のように受け取る変数や定数などにデータ型を指定してあげて下さい。
let n :Int = test()
print(n) // 『1』が出力されます。

let s :String = test()
print(s) // 『初音ミク』が出力されます。

なので「関数を実行させた際の返り値をデータ型の指定がある変数や定数とかで受け取ってあげる」ようにしてあげないとNGです。ここ間違いやすいので気をつけて下さい。

というわけで『オーバーロード』の記述方法とかはこんな感じになります。ここまでは大丈夫そうでしょうか。

続いて肝心な『オーバーロード』の使い所になりますが、これは「いじることができない元々用意された関数とかをハックしたい」というパターンに使われることが多いです。

ちょっと以下のサンプルを見てみて下さい。

func test(a: String) { // この関数はいじれないものとします。
    print("これは文字列です。")
}

var val = "初音ミク" // ここが変動するものとします。

test(a: val) // ここもいじれないものとします。

上記の関数『test』と『test(a: val)』という部分は何らかの理由でいじることができないと仮定してみましょう。

それはアップルさんが元々用意してくれている関数だったり、ライブラリとかで読み込ませた関数かもしれません。

そして変数『val』に数値が来る可能性が出てきたのでちょっと処理を分岐させたい、といった場合に『オーバーロード』が使われます。

func test(a: String) { // この関数はいじれないものとします。
    print("これは文字列です。")
}

func test(a: Int) { // このように『オーバーロード』を上手く使うことで元の処理をいじることなく機能を増やす事ができます。
    print("これは数値です。")
}

var val = 1 // ここが変動するものとします。

test(a: val) // ここもいじれないものとします。

「元の処理をいじらなくてもOK」ってところがミソですね。

『オーバーロード』はそこまで使用頻度が高いわけではないですが、iPhoneアプリの開発とかをしているとアップルさんが用意してくれる関数とかをちょいと上書きする必要がでてきたりします。そんな時に『オーバーロード』を知らないと手詰まりになってしまう場合があるのでバッチリマスターしてしまって下さい。

というわけで以上です。続いての記事では『if文』についてやっていきましょう。では失礼します。

この記事は桜舞が執筆致しました。

著者が愛する小型哺乳類

桜舞 春人 Sakurama Haruto

ISDN時代から様々なコンテンツを制作しているちょっと髪の毛が心配な東京在住のプログラマー。生粋のロングスリーパーで、10時間以上睡眠を取らないと基本的に体調が悪い。好きなだけ寝れる生活を送るのが夢。ゲームとスポーツと音楽が大好き。誰か髪の毛を分けて下さい。

記事の間違いや著作権の侵害等ございましたらお手数ですがこちらまでご連絡頂ければ幸いです。