[iOS 8] Android脳に効く!新言語「Swift」超入門 #4 関数とクロージャ

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

関数

第一級オブジェクト

Swiftの関数は第一級オブジェクトとして扱う事ができます。つまり、関数を「一つのオブジェクト」として扱えるということです。そのため、関数を変数に格納したり引数で関数をやりとりするようなことが可能になります。

関数の定義

 関数定義の文法

func_syntax

関数を定義するにはfuncキーワードを使います。Javaのメソッドと同じように引数が必要ない場合は引数を記述しません。また、Javaのメソッドで値を返さない場合は返り値の型をvoidとしていましたが、関数が値を返さない場合は「->返り値の型」を記述しません。

Swift Code

var name = "Taro"

// 最も単純な関数
func rename() {
    name = "Jiro"
}

// 関数を呼び出します
rename()

println(name) // Jiro

引数も返り値もない単純な関数を定義してみました。次は、引数と返り値をあわせて定義してみます。

Swift Code

var name = "Taro"

// 名前を変更すると番号を返す関数を定義します
func rename(newName: String) -> Int {
    // 引数の値をnameに代入
    name = newName
    // 番号を格納する変数を宣言
    var number: Int
    
    switch newName {
    case "Taro":
        number = 1
    case "Jiro":
        number = 2
    case "Saburo":
        number = 3
    default:
        number = 0
    }
    // 新しい名前にマッチする番号を返す
    return number
}

var number = rename("Jiro")

println("名前は\(name)で、番号は\(number)です。")
// 名前はJiroで、番号は2です。

複数の値を返す関数

Swiftでは複数の値を返却する関数の定義ができます。ここではタプル型が活躍します。

Swift Code

// タプル型の定数を宣言
let classmethodInfo = ("classmethod.inc", 35.697239, 139.774719)

// タプル型を返す関数を定義します
func getClassmethodInfo() -> (name:String, lat:Double, lng:Double)  {
    return classmethodInfo
}

println("社名: \(getClassmethodInfo().name)")
println("緯度: \(getClassmethodInfo().lat)")
println("経度: \(getClassmethodInfo().lng)")

// 社名: classmethod.inc
// 緯度: 35.697239
// 経度: 139.774719

このように、一度に複数の異なる型の値を返却することができます。

CHECK!
タプル型とは、複数の値をまとめて扱うことのできる簡易的なデータ構造です。このとき、それぞれの値の型はバラバラでも構いません。タプルの値を扱うには配列のようにインデックスを用いる方法と、あらかじめ値に名前を付けておいてその名前を用いる方法が用意されています。

関数をオブジェクトとして扱う

冒頭で紹介したように、関数はオブジェクトとして扱うことができます。そのため、引数で利用したり、返却値として関数を返すことも可能です。

実際にはどのように扱うのか見ていきたいと思います。

Swift Code

// 引数の関数をかえる事で合否判定の難易度を変更できる
func determineAcceptance(score: UInt, determine: UInt -> Bool) -> String {
    if determine(score) {
        return "合格"
    } else {
        return "不合格"
    }
}

// 難易度:低
func determineEasyBorder(score: UInt) -> Bool {
        return score >= 50
}

// 難易度:高
func determineDifficultBorder(score: UInt) -> Bool {
    return score >= 80
}

determineAcceptance(50, determineEasyBorder) // 合格

determineAcceptance(60, determineDifficultBorder) // 不合格

determineAcceptance(...)を呼び出す時には、UInt型のスコアとUInt型を引数に取りBool型を返却する関数が求められます。そこで[11,20行目]で定義している判定基準のことなる関数を与えます。

結果的に[28行目]では判定基準のやさしい関数を使っているのでスコア50で合格になり、[30行目]ではスコア60であるにもかかわらず、判定基準が厳しい関数を使用しているので不合格の判定となりました。

このように、関数を部品のように扱い状況によって使い分けることができます。

クロージャ

クロージャとは関数オブジェクトのひとつです。クロージャを関数の引数に渡すことで関数の挙動を変更するといったことが可能になります。

先ほどのサンプルコードを用いた例です。

Swift Code

// 引数の関数をかえる事で合否判定の難易度を変更できる
func determineAcceptance(score: UInt, determine: UInt -> Bool) -> String {
    if determine(score) {
        return "合格"
    } else {
        return "不合格"
    }
}

// 難易度:低
func determineEasyBorder(score: UInt) -> Bool {
        return score >= 50
}

// 難易度:高
func determineDifficultBorder(score: UInt) -> Bool {
    return score >= 80
}

determineAcceptance(50, determineEasyBorder) // 合格

determineAcceptance(60, determineDifficultBorder) // 不合格

determineAcceptance(30, {(score: UInt) -> Bool in return score >= 0}) // 合格

[32行目]であらかじめ定義されていない判定基準度を設定しています。determineAcceptance(...)の第二引数はUInt型の引数を取り、Bool型を返却する関数です。すなわち、この条件に合った関数をオブジェクトとして渡してあげればいいということです。そこで、[32行目]ではその場で関数を定義して引数に渡しているような感じで、引数、返り値と本体の処理をinで区切って記述します。

まとめ

関数の扱いになれるのは少し大変かもしれませんが、その柔軟性、拡張性の高さは非常に魅力であると思います。

ここらへんの機能がAndroid開発でも使えたらなんて思いますが、そう簡単にいかないのが現実です。気長に待ってみましょう。

ということで、関数とクロージャについてでした。次回は、クラスと構造体についてです。

バックナンバー

[iOS 8]Android脳に効く!新言語「Swift」超入門 #1 変数の宣言と型
[iOS 8]Android脳に効く!新言語「Swift」超入門 #2 Optional基礎
[iOS 8]Android脳に効く!新言語「Swift」超入門 #3 制御構造
[iOS 8]Android脳に効く!新言語「Swift」超入門 #4 関数とクロージャ
[iOS 8]Android脳に効く!新言語「Swift」超入門 #5 クラスとストラクチャ