Codable Tech Blog

iPhoneアプリケーション開発と AWS(Amazon Web Service)活用に関する記事を配信

関数(Function)

関数は特定のタスクを実行するためのコードの塊です。特定のタスクを実行するためのコードの塊である関数には名前を付けることができます。タスクを実行したい時にはその名前を指定すれば関数を呼び出すことができます。以降では、関数の定義、呼び出し方、関数の性質についてみていきます。

関数の定義

関数は次のような書式で定義します。

func 関数名(パラメータ名:パラメータの型、パラメータ名:パラメータの型、...)->戻り値の型{
    文
    return 戻り値
}

関数はfuncキーワードの後に関数の名前を指定します。名前は具体的に定義する処理に応じて適切な名前を設定します。例えば、平均を求める処理ならばavgという関数名を付けるという具合です。関数は入力情報として複数の型の値を受け取ることができます。これはパラメータと呼ばれます。パラメータは関数名の後に「 ( 」を置いて、「パラメータ名:型」の形で記述します。パラメータを記述し終えたら、「 ) 」を置きます。また、関数は処理を実行し終わった後、呼び出し元に値を返すことができます。これは戻り値と呼ばれおり、アロー演算子->の後に戻り値の型を記述します。関数の処理は { から } の間(関数のブロック)に記述します。
次の例は関数名がsayHello、パラメータにString型、戻り値にString型を返す関数です。

関数を定義する時、キーワードfuncを記述し、次に関数名sayHelloを指定します。次に関数名の後丸括弧()の中にパラメータを指定し、戻り値の型はアロー演算子->の後に続けて配置します。関数のブロックには特定のタスクを実行するためのコードを記述します。なお、関数のパラメータ(ここではpersonName)は関数のブロックだけでしか利用出来ないことに注意してください。最後にreturn文を使って関数の呼び出し元に返却したい値を指定します。ここでは定数greetingの値が関数の呼び出し元に返却されます。

関数の呼び出し方

関数を利用するためには関数名を指定し、必要なパラメータを渡してあげる必要があります。関数にパラメータを渡す際、パラメータが定義されている順番通りに渡してあげる必要があります。関数は次のような書式で呼び出します。

関数名(関数に渡す値1、関数に渡す値2...)

次の例はsayHello関数を呼び出す例です。sayHelloの後に()を付け、()の中にString型のパラメータを渡すことで呼び出すことができます。

上記の例では文字列aiueoをパラメータに指定してsayHello関数を呼び出しています。この結果、sayHello関数のpersonNameパラメータに文字列aiueoが代入されます。このため、定数greetingの値は"Hello,aiueo"になります。

複数の入力パラメータ

sayHello関数は単一の入力パラメータを持つ関数でした。パラメータはカンマで区切ることによって複数のパラメータをもつことができます。次の例はInt型のパラメータを2つ持ち、戻り値としてInt型の値を返すcalcRange関数の例です。

パラメータのない関数

関数のパラメータは必須ではありません。もし、パラメータを受け取る必要がなければ、関数にパラメータを配置する必要はありません。次の例はパラメータのないsayHello関数の定義です。

戻り値

関数の呼び出し元に値を返したい時はreturn文を利用します。return文を利用することで呼び出し元に値を返すことができますが、返す値の型は関数定義時に指定した戻り値の型と一致していなければいけません。次の例ではString型を戻り値の型として指定しているのでreturnに指定する値の型もStringが型でないといけません。

関数が戻り値を返す場合、呼び出し元で関数が返した値を受け取ることができます。一般的には次のように戻り値を定数や変数に代入します。

しかし、関数の戻り値を以降のプログラムで使う必要がないのであれば、わざわざ定数や変数に代入する必要はありません。例えば、戻り値の値を出力したいだけの用途であれば次のように記述できます。

上記の例ではまず、getFullName関数が実行されます。getFullName関数が実行された後、戻り値としてString型の値が返されます。この返された値がprintln関数のパラメータとして設定されます。結果として、コンソールにフルネームが出力されます。また、呼び出し後、返却される関数の戻り値が不要であれば次の例のように戻り値を無視してかまいません。

戻り値のない関数

戻り値も関数にとって必須ではありません。戻り値がない関数の場合、アロー演算子と戻り値の型を置く必要はありません。次のsayGoodbye関数は戻り値をもたず、パラメータを一つだけ持つ関数の例です。

複数の戻り値をもつ関数

タプルを利用することで複数の値を返却する関数を定義することができます。次の例はInt型の配列から最小値と最大値を見つけ、最小値と最大値の組み合わせをタプルとして返却します。

関数の呼び出し後、戻り値がタプルとして返却されるので定数boundsで受け取ります。タプル型の戻り値は「定数名or変数名.関数の戻り値で定義された名前で」アクセスすることができます。ここでは最小値を表すタプルの第1パラメータ名がmin、最大値を表すタプルの第2パラメータ名がmaxなので、それぞれbounds.min、bounds.maxと表現できます。

オプショナル(Optional)型の戻り値

nilをとる可能性のある値の場合、オプショナル(Optional)型として戻り値を定義します。オプショナル(Optional)型は戻り値の型に続けて?をつけます。

戻り値の型?

次のgetSum関数は整数型の配列をパラメータとして受取り、渡された配列が空の場合はnil、要素が1つ以上存在すれば要素の合計値を返します。getSum関数を呼び出す時、オプショナルバインディングを利用しています。オプショナルバインディングを利用して、もし、値がnilであれば、配列の要素が空であるメッセージを表示し、空でなければ合計値を表示しています。

外部パラメータ名

外部パラメータはユーザーが関数を呼び出す際に、パラメータ名と値を同時に付けて呼び出すことを可能にする機能です。外部パラメータを定義するには、次のように関数を定義する時に通常のローカルパラメータの前に外部パラメータ名を配置します。なお、外部パラメータとローカルパラメータはスペースで区切る必要があります。

func 関数名(外部パラメータ名 内部パラメータ名: パラメータの型) {
    文
}

次の例は2つのString型のパラメータを受け取る関数に外部パラメータを付けた例です。

この関数を呼び出す時は以下のように呼び出します。

外部パラメータをつけることで可読性の高いコード(ここでは関数の定義を見る必要なく、パラメータの意味を把握できる)を記述することができます。

外部パラメータの省略

もし、ローカルパラメータ名と外部パラメータ名の名前が同じならば、同じ名前を2度書く必要はありません。その代わり、パラメータの前に#をつけましょう。こうすることでローカルパラメータと外部パラメータに同じ名前が自動で付けられます。

デフォルトパラメータ

関数ではよく定義時によく利用される値をデフォルト値として与えることができます。デフォルト値が与えられた関数の場合、関数呼び出し時にパラメータを指定しなれければ定義時に指定されたデフォルト値がパラメータに代入されます。デフォルト値をもつ関数は次のように定義できます。

func 関数名(パラメータ名: パラメータの型="デフォルト値") {
    文
}

次の例ではgetFullName関数のパラメータfirstNameとlastNameにデフォルト値を与えた例です。

getFullName関数はデフォルト値が与えられていますので、パラメータを指定せずgetFullName関数を呼び出した場合、firstNameには"Taro"、lastNameには"Yamada"が代入されます。

デフォルト値と外部パラメータ

Swiftではデフォルト値を与えた場合、自動で外部パラメータも設定してくれます。外部パラメータはローカルパラメータ名と同じになります。次の例ではgetFullName関数のパラメータfirstNameとlastNameにデフォルト値を与えた例です。

上記の場合、外部パラメータとしてfirstNameとlastNameが自動で定義されています。このため、getFullName関数をパラメータを指定して呼び出す時は外部パラメータ名を指定して呼び出してあげる必要があります。

可変パラメータ

関数を定義する時、いくつのパラメータを受け取れるようにするべきか事前に決められないことがあります。例えば、コンソール上に変数の値を出力する状況をを考えてみましょう。コンソールに変数の値を出力する時、一つの変数の値だけ出力すればよい時もあれば、二つの変数の値、三つの変数の値を出力したい時もあります。このようにプログラムを実行する状況によって受け取るパラメータの個数が変わる時は、可変パラメータを利用するのが便利です。可変パラメータは0個以上の値を受け取れるパラメータです。可変パラメータを持つ関数は次のようにパラメータの型に「...」を付けることで定義できます。

func 関数名(パラメータ名: パラメータの型...) {
    文
}

なお、可変パラメータに渡される値は関数の中で配列として取得できます。次の例はString型の可変パラメータを受け取る関数です。

可変パラメータに渡される値は関数の中で配列として取得できるのでした。このため、この例では可変パラメータの配列の値を全て列挙して、結合した文字列を返しています。

可変パラメータで定義された関数の呼び出し

関数を呼び出す時、可変パラメータには0個以上の任意のデータを渡すことができます。次の例ではjoinStrs関数に3つのString型のデータを渡しています。

変数としてのパラメータ

関数のパラメータはデフォルトでは定数として定義されます。このため、関数のボディ部で値を変更するとコンパイルエラーが発生します。もし、変数を関数のパラメータとして定義したい場合、パラメータ定義時にvarをつけます。こうすることで、パラメータは変数として扱われます。パラメータは呼び出し時に渡された値をコピーして作成するので関数内でパラメータの値を変更しても呼び出し時に渡した値に対して何の影響も与えません。次の関数は渡された文字列を指定された文字列で囲む関数です。

surroundTargetStringの第1パラメータにoriginalStringを渡していますので、targetStrにはhelloが代入されます。surroundTargetString内ではtargetStrの値を両端を*で囲んだ文字列*hello*に更新しています。surroundTargetString関数呼び出し後、println関数でoriginalStringとresultStringを表示しています。ここで注目して欲しいのはoriginalStringの値がhelloであることです。呼び出し元の変数の値と関数のパラメータの値は独立しているため、関数内でパラメータの値を変更しても呼び出し元の変数には影響を与えていないことがわかります。

In-Outパラメータ

変数としてパラメータを扱ったとしても、呼び出し元の変数の値と関数のパラメータの値は独立しているため、お互いに影響を及ぼしません。呼び出し元の変数と関数のパラメータの間で値を共有する関数を作成したい場合、inoutキーワードを利用することで実現することが出来ます。

func 関数名(inout パラメータ名:パラメータの型)->戻り値の型{
    文
    return 戻り値
}

inoutキーワードがついている関数を呼び出す時、渡す値は変数でなければならないことに注意してください。定数やリテラルをinoutキーワードのついたパラメータに渡すことはできません。さらに、関数呼び出し時に変数を渡すとき、変数名の前に&をつける必要があることに注意してください。次の例は2つの変数の値を入れ替えるswapTwoInts関数の例です。

swapTwoIntsに渡している値が変数であること、呼び出し時に&を付けていることに注意してください。swapTwoInts関数では渡された2つの値を入れ替えています。swapTwoInts関数を呼び出した後、それぞれの変数を出力すると、呼び出す元の変数の値も変更されていることが確認できます。

関数の型

Swiftfでは関数も今まで扱ってきた整数や文字列同様、一つの値として扱うことができます。値として扱うことができるということは型を持っていることを意味しています。すべての関数の型はパラメータの型と戻り値の型に基づく形で宣言することができます。関数の型は次のようにになります。

(パラメータの型1,パラメータの型2,...)->戻り値の型

下記はInt型のパラメータを2つ持ち、Int型の戻り値を返す関数です。この場合の型は (Int, Int) -> Intになります。「2つのInt型のパラメータをもち、Int型の戻り値を返却する関数型」ということになります。

下記はパラメータおよび戻り値をもたない関数です。この場合のは () -> ()になります。「パラメータはもたず、戻り値がVoidの関数型」ということになります。

関数型の宣言

関数型は他の型と同じように変数や定数、関数のパラメータの型として利用できます。下記は2つのInt型のパラメータをもち、Int型の戻り値を返す関数型の変数mathFunctionを宣言しています。

この例では変数mathFunctiohにaddTwoInts関数を代入しています。これはaddTwoInts関数が2つのInt型のパラメータをもち、Int型の戻り値を返す関数型の値であることを意味しています。mathFunctionにはaddTwoInts関数が代入されているのではmathFunctionという名前でaddTwoInts関数を呼び出すことができます。また、同じ型で異なる処理の関数を代入しなおすこともできます。

関数型の定数や変数を定義する時、これまで同様に型推論を利用して、型注釈部分を省略することが可能です。

パラメータとしての関数型

関数のパラメータとして関数型を利用することもできます。次の関数は第1パラメータに関数型、第2パラメータ、第3パラメータにInt型をとるprintMathResultの例です。

最初のパラメータmathFunctionは(Int, Int) -> Int型の関数型パラメータです。このパラメータにaddTwoInts関数を渡しています。printMathResultは単純にmathFunctionの結果を出力するだけです。言い換えると(Int, Int) -> Int型の関数を呼び出して結果を出力するだけです。関数型のパラメータを受け取るメリットは関数の機能の一部を呼び出し側に委譲することが出来る点です。例えば、printMathResulutの呼び出しは次のように変更しても問題ありません。

このように、呼び出し側が状況に応じて関数の処理の一部を変更出来るのがパラメータとして関数型を提供するメリットです。

戻り値としての関数型

関数型を関数の戻り値として提供することも可能です。次の関数はaddTwoIntsとmultiplyTwoIntsのどちらを選択できる関数selectTwoIntの例です。

addTwoInts関数とmultiplyTwoInts関数はどちらも(Int,Int) -> Intです。このため、selectTwoIntFunc関数の戻り値に(Int,Int) -> Int型を定義して、パラメータの値に応じて、addTwoInts関数かmultiplyTwoInts関数のどちらを返すように定義しています。呼び出し側は次のようにselectTwoIntFunc関数を呼び出すことで(Int,Int) -> Int型の値を受け取ることができます。

ネストされた関数

ここまで見た関数はすべてグローバルスコープに定義されたグローバル関数です。関数は関数内部でも定義することができます。これをネスト関数とよびます。ネスト関数は外部からは隠されていますが、ネスト関数を囲んでいる関数からは呼び出すことができます。ネスト関数を囲んでいる関数のことをエンクロージング関数と呼びます。エンクロージング関数はネスト関数を戻り値として返すことができます。このため、呼び出し元でネスト関数を利用することができます。次の例はselectTwoIntFunc関数の中にaddTwoInts関数とmultiplyTwoInts関数の両方を定義し、値に応じていずれかの関数を戻り値として返しています。

関数がネストできることの効能はクロージャの箇所で説明しますので、今はこんなことが出来るんだと知っておいてもらえれば充分です。