Swiftの関数(Functions)

Swiftの関数(Functions)

関数(functions)です。関数が理解できれば、構造体(structure)とクラス(class)まで、あと一歩です。ここではSwiftにおける関数の定義から始めて、関数の呼び出し、関数の引数や戻り値に関する詳細、引数の名前をどうつけるか(呼び出し用と内部使用パラメータ)、引数を関数の外に持ち出すにはどうするかについて説明します。さらに「function types」と呼ばれる、いわゆる「関数型」という特殊な型、関数の入れ子(nested functions)についても例を交えながら詳しく説明します。

関数とは何か?

関数(function)とはなんでしょうか?定数や変数は値(value)を格納する箱のようなものですが、関数は値だけでなく演算などの「機能」を包む箱のようなものになります。

数学(算数)で例えるのが最も分かりやすいですが、例えば

y = x2

というのは「xの2乗がyになる」という立派な関数です。プログラミング的に解釈すると

xの2乗をyに代入する

となります。これを図示すると、下のグラフのようになります。

y=x^2をグラフ化

グラフにすると分かりやすいですよね。例えば、xが3の時yは9になります。

数学的な関数の一般化は次のような表現になります。

y = f(x)

一般的な機能をf(....)で表現しています。xは、この後説明する引数(parameter)に対応します。ここでfは、もちろんfunctionの頭文字です。

プログラミングにおける関数は、数学的な演算だけに限らず、様々な処理を行うことができますが、上記の数学的な関数を意識しておくと理解しやすいと思います。

関数の定義、関数の呼び出し

ここでの記述はSwift 3をベースにしていますので、Swift 2.xではコンパイルが通らない可能性があります。最大の違いはパラメータ名指定です。Swift 2.xまでは、関数が持つパラメータの1つ目だけは例外で、デフォルトではパラメータ名を指定せずに使用することが可能でした。Swift 3から全てのパラメータが同等の扱いになったので、1つ目のパラメータも名前を指定しないとコンパイルエラーになります。

関数の定義

いきなりですが、関数の例です。

// 関数の例
func hello(name: String) -> String {
    let greeting = "Hello world! " + name
    return greeting
}

関数の定義にはfuncキーワードを使います。また、関数には固有の名前(function name)を付けます。ここではhelloです。Swiftでは、関数の名前は小文字から始めます。

上記の例のように、基本的な関数定義構文は

// 関数の基本的な構造
func functionName(parameters) -> returnType {
    statements
}

という感じになります。

関数には戻り値(return type)があります(返り値とも呼びます)。これを-> returnTypeで指定します。指定するのは型で、上記の例ではStringが戻り値になります。また、関数はインプットとして引数(ひきすう)を取ります。引数は関数名の直後のカッコ内()に指定します。戻り値と引数については後で詳しく説明します。

このように、関数の定義は

関数がどんな処理をして、どんなパラメータを受け取り、どんな戻り値を返すか

をユーザに示すものです。

もちろん「どんな処理をするか」というのは、どういう名前をつけるかに依存しますので、できる限り関数内部の処理を端的に表現する名前を付けたいですね。

関数の呼び出し

早速さっき作った関数を使ってみます。関数を使用することを、良く呼び出し(call)と言います。

// 関数の呼び出し(calling function)
let greetingToTarou = hello(name: "Tarou") // 結果を定数に代入(初期化)
print(greetingToTarou)
//"Hello world! Tarou"と表示

print(hello(name: "Hanako"))
//"Hello world! Hanako"と表示

関数の引数(インプット)を指定する時は、その引数の値だけではなく、名前(今はname)も同時に指定します。

関数の戻り値はStringですから、結果を代入したgreetingToTarouStringです。またhello(name:)関数はStringを返すので、print()関数の引数として直接渡すことも可能です。

print()関数の場合、パラメータ名を渡していないのが不思議な気がしますが、これについては関数の引数のページで説明します。

hello(name:)関数の中身を詳しく見てみると、先ず

let greeting = "Hello world! " + name

Stringの連結をしています。ここでは"Hello world! "と、インプットされた文字列nameを連結しています。

さらに、連結された文字列greetingを戻り値として返しています。

return greeting

上記の例でも分かるように、関数は繰り返し使用できます。また、関数コールのたびに異なるパラメータ(ここではTarouHanako)を受け取って、それをきちんと処理していることが分かります。

まとめ

  • 関数の定義にはfuncキーワード、関数固有の名前が必要
  • 関数の名前(function name)は小文字から始める決まり
  • 関数の定義と呼び出しの際、かっこ()を省略することはできない。パラメータや戻り値の有無は関係ないので注意