Swift の関数

ここでは Swift のユーザー定義関数についてご説明します。

Swift のユーザー定義関数とは?

まず、プログラミングで関数というのは、特定の処理をするひとまとまりのコードに名前をつけて呼び出せるようにしたものです。

引数というのは、実行時に関数に呼び出し元から渡される値とそれを受け取る関数側の変数のことです。


Swift には、既に定義された、たくさんの組み込み関数があり、必要に応じて呼び出して使うことができます。

例えば、出力するのに良く使う print() もライブラリの組み込み関数です。


Swift でも、他のプログラミング言語と同様に、特定の処理をするひとまとまりのコードをユーザー定義関数として定義しておいて、呼び出して使うことができます。

組み込み関数と同様に、ユーザー定義関数に引数を渡すこともできますし、戻り値を返すこともできます。

プログラムを書いていて、繰り返し同じコードを書いているなと感じた時は、ユーザー定義関数を作って、それを呼び出すようにしたほうが良いことが多いです。


それでは、Swift でユーザー定義関数について詳しく学んでいきましょう。


Swift のユーザー定義関数を定義する

Swift で関数を定義するには、func というキーワードを使って、次のように定義します。

func 関数名(引数名1: 引数1のデータ型, 引数名2: 引数2のデータ型, ...) -> 戻り値のデータ型 {
    関数のコードブロック
    ...
    return 戻り値
}

引数と戻り値は必要なければ、なくて大丈夫です。

関数を定義しただけでは、その中のコードは実行されず、呼び出されて初めて関数のコードが実行されます。

ユーザー定義関数を呼び出す方法は組み込み関数と同じで、関数名(引数名1: 引数1, 引数名2: 引数2) のように呼び出せます。


呼び出し側で引数名を指定しないようにしたい時は、次のように引数の定義の箇所で _ を追加します。

この場合、第一引数が引数名1に入って、第二引数が引数名2 に入って、関数のコードブロック内で利用できます。

func 関数名(_ 引数名1: 引数1のデータ型, _ 引数名2: 引数2のデータ型, ...) -> 戻り値のデータ型 {
    関数のコードブロック
    ...
    return 戻り値
}

では、まずは引数のない、Hello! という文字列を出力するだけのシンプルな greet という関数を定義して呼び出してみましょう。

func greet() {
    print("Hello!")
}

greet()

実行結果は次のようになります。 5 行目の greet() でユーザー定義関数が呼び出され、print("Hello!") が実行されます。

Hello!

Swift の ユーザー定義関数の引数

先ほどは、引数の無いユーザー関数を定義して、呼び出してみましたが、今度はユーザー定義関数に引数を渡してみましょう。

greet() 関数に first_name と last_name という引数を追加して、それを出力するように変更すると次のようになります。

func greet(fristName: String, lastName: String) {
    print("Hello! I'm \(fristName) \(lastName).")
}

greet(fristName: "Jun", lastName: "Sasaki")
greet(fristName: "Ryo", lastName: "Tanaka")

実行結果は次のようになります。渡した引数の値によって、出力される名前が変わっていますね。

Hello! I'm Jun Sasaki.
Hello! I'm Ryo Tanaka.

Swift のユーザー定義関数の引数のデフォルト値

ユーザー定義関数で定義した引数は必須で、呼び出す時に値を渡さないとエラーになります。

関数を定義する時に引数にデフォルトの値を指定しておくことによって、関数を呼び出す時にその引数を省略することも可能です。


例えば、4 つの値を受け取って足すだけの関数を定義して、3つ目と4つ目の引数のデフォルト値を 0 にしてみましょう。

func add(value1: Int = 1, value2: Int, value3: Int = 0, value4: Int = 0) {
    print(value1 + value2 + value3 + value4)
}

add(value1: 1, value2: 2)
add(value1: 1, value2: 2, value3: 3)
add(value1: 1, value2: 2, value4: 4)

実行結果は次のようになり、add() を呼ぶ時に、デフォルトの指定されている引数は渡さなくてもエラーならず、渡さなかった引数は 0 として計算されていますね。

3
6
7

Swift のユーザー定義関数の可変長引数

引数の数が何個になるかわからない時には、引数のデータ型の後ろに ... をつけることによって、引数の数を可変にすることができます。

... をつけると、引数を Array の定数として受け取り、インデックスを指定したり、ループをしたりすることによって、受け取ったそれぞれの引数が使えます。


例えば、values という名前で渡した数字を全て足した合計を出力するには、次のようにします。

func add(values: Int...) {
    var total = 0
    for value in values {
        total += value
    }
    print("Total: \(total)")
}

add(values: 1, 2, 3)
add(values: 1, 2, 3, 4, 5)

実行結果は次のようになります。 values の値の数が何個あっても Int である限りエラーにはならず、計算結果が出力されています。

Total: 6
Total: 15

Swift のユーザー定義関数の戻り値

ユーザー定義関数から戻り値を返すには引数に続いて「-> 戻り値のデータ型」のようにデータ型を指定しておき、return 文で値を返します。

例えば、先ほど引数で渡した数字を全て足して合計を出力した関数を、合計を戻り値として返すように変更すると次のようになります。

func add(values: Int...) -> Int {
    var total = 0
    for value in values {
        total += value
    }
    return total
}

let total = add(values: 1, 2, 3, 4, 5)
print("Total: \(total)")

実行結果は次のようになり、add() 関数が total を戻り値として返しているのがわかりますね。

Total: 15

ユーザー定義関数から複数の戻り値を返す

Swift のユーザー定義関数から複数の戻り値を返したい時は、タプルが使えます。

例えば、name という文字列を受け取って、" " でスプリットし、二つに分けられた時だけ、ひとつめの文字列を lastName、ふたつめの文字列を firstName として戻り値として返したい時は次のようにできます。

func splitName(name: String) -> (lastName: String, firstName: String) {
    let names = name.split(separator: " ")
    if names.count == 2 {
        return(String(names[0]), String(names[1]))
    } else {
        return("", "")
    }
}

let (lastName, firstName) = splitName(name: "Saki Nagano")
print("lastName = \(lastName), firstName = \(firstName)")

実行結果は次のようになります。

lastName = Saki, firstName = Nagano

呼び出し側の戻り値を受け取る箇所は let n = splitName(name: "Saki Nagano") のようにして、n.lastName、n.firstName のように受け取った値を使うこともできます。


inout で引数を「参照渡し」にする

Swift の入力引数が関数の中で変更できるか、また変更した値が関数の呼び側に反映されるかどうかというのは、そのデータ型が参照型かどうかで変わってきます。

関数の中で入力引数が変更できるかは、let で定義した定数の値が変更できるかと同じです。

例えば、class は参照型なので let で定義しても固定されているのはインスタンスへの参照で、その中のプロパティの値は変更できるので、引数として渡した場合、関数の中でもプロパティの値を変更でき、呼び出し側にもその変更が反映されます。

Swift の関数 1


Swift では、Int、String、Double などのベーシックなデータ型の他、Array、Struct、Enum、Tuple、Dictionary など全て参照型ではなく値型です。

値型の入力引数を関数内で変更しようとするとエラーになり変更できません。


時には、値型の入力引数を「参照渡し」して、関数内で値を変更し、その変更を呼び出し側にも反映させたいことがあるかもしれません。

そんな時は inout キーワードを入力の引数のデータ型の前につけ、呼び出し側の変数の前に & をつけることによって、参照渡しにすることができます。


例えば、先ほどの splitName という名前の関数の入力引数 name を参照渡しにして、split した結果が二つではなかった場合に引数を "Invalid" という文字で上書きしています。

func splitName(name: inout String) -> (lastName: String, firstName: String) {
    let names = name.split(separator: " ")
    if names.count == 2 {
        return(String(names[0]), String(names[1]))
    } else {
        name = "Invalid"
        return("", "")
    }
}

var name = "Saki"
print("name before: \(name)")

let nameSplit = splitName(name: &name)

print("name after: \(name)")

実行結果は次のようになり、関数を呼んだ後、name の値が変更されていることがわかります。

name before: Saki
name after: Invalid

以上、Swift のユーザー定義関数についてご説明しました。

© 2024 iOS 開発入門