関数とクロージャ -Swift編-
今回は、関数とクロージャについて勉強します。
まず、関数とクロージャについてちょっとわからなかったので、調べてみました。
関数 関数とは、一般的に引数を与えると返り値が返ってくる物を言います。例えば、Name = "Mike"という引数を関数に与えると、"Hello Mike"と返す動作をするユニットのことを関数といいます。
クロージャ クロージャは、関数のインスタンスを作成した時に環境変数を与え実行される関数みたいなものをいいます。Appleは
Closures are self-contained blocks of functionality that can be passed around and used in your code. Closures in Swift are similar to blocks in C and Objective-C and to lambdas in other programming languages.
述べています。
関数とクロージャ
関数
関数の定義には"func"を関数名に前置します。また、その後に"->"を使って返り値の型を定義します。以下に、サンプルコード作りました。関数の引数に、足し算をする数字を入れると足し算した値が返ってきます。
func plus(num1: Int, num2: Int) -> Int { return num1 + num2 } print(plus(1, num2: 2))
この場合、返り値の型はint、引数もそれぞれint型です。
ここで、注意しなくてはいけないのは引数2つめの引数は、引数名を添えなくてはいけないということです。なぜ、こういう仕組みにしたのかはよく分かりません(分かる方いらっしゃいましたら、教えていただけると幸いです)
実は、同じ方であれば以下の様な方法でも引数を定義することが出来ます。例えば
func sum(numbers: Int...) -> Int { var sum = 0 for number in numbers { sum += number } return sum } print(sum()) print(sum(42, 50, 10, 128))
のように、関数の引数として"numbers: Int..."とすることで、複数の引数(int型)を定義することが出来ます。個人的に、引数の個数を決定しなくていいところが便利かなって思いました。
関数に返り値を複数与える
Swiftでは返り値を複数にすることが簡単にできます。
また、引数に配列を入れることも可能です。まずは、サンプルコードを紹介したいと思います。
func calculateStatistics(scores: [Int]) -> (min: Int, max: Int, sum: Int, ave: Float) { var min = scores[0] var max = scores[0] var sum = 0 var ave: Float = 0 for score in scores { if score > max { max = score } else if score < min { min = score } sum += score } ave = Float(sum) / 5 return (min, max, sum, ave) } let statistics = calculateStatistics([5, 19, 66, 21, 3]) print(statistics.sum) print(statistics.2) print(statistics.ave)
基本的な関数の定義の仕方は、先述した通りです。
この中で
func calculateStatistics(scores: [Int]) -> (min: Int, max: Int, sum: Int, ave: Float)
の部分がミソですね。->(min: Int, max: Int, sum: Int, ave: Float)で返り値の型を定義しています。
関数内でゴニョゴニョ計算した後、次のように呼び出すことで返り値を得ることが出来ます。
let statistics = calculateStatistics([5, 19, 66, 21, 3]) print(statistics.sum) print(statistics.2) print(statistics.ave)
つまり、calculateStatisticsという関数で計算した内容をstatisticsに代入して、そのオブジェクトstatistics.sumであったり、statisticsの2番めの要素(ここでは、sumですね)statistics.2を呼び出すことで、該当の返り値を得ることが出来ます。
関数の入れ子(ネスト)
Swiftでも関数を入れ子にすることが出来ます。つまり、関数の中に関数を作る事ができます。
func increaseTen() -> Int { var y = 0; func add() { y += 10 } add() return y } print(increaseTen())
今回作成したコードはほんとうに意味がありませんが、increaseTenという関数の中にaddという関数があります。increaseTen関数が呼び出された時に中にあるadd関数も呼び出されます。
関数を返す
今まで書いた関数は first-class typeの関数で、関数を呼び出した時に関数を返すことが出来ます。(僕も、理解が追いついていないところがあります)
func halfNumber() -> ((Int) -> Float) { func half(number: Int) -> Float { return Float(number) / 2 } return half } var Half = halfNumber() print(Half(11))
このように、halfNumber関数を呼び出した時に、half関数を返します。つまりHalfはhalf関数と同義になるんですね。そうすると、Halfは関数となり引数を渡すとhalf関数で定義した処理が実行できるようになります。
今日はつかれたのでここまで。 何か、おかしいところやわからないところありましたら、コメントいただけると嬉しいです。