SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

アップルの新プログラミング言語「Swift」を探検しよう

Swiftのパワフルな記述力が秘められた
「関数」と「クロージャ」

アップルの新プログラミング言語「Swift」を探検しよう 第2回


  • X ポスト
  • このエントリーをはてなブックマークに追加

訂正:以下「クロージャ表現」という表記を「クロージャ式」と改めました(2014/7/1)

クロージャ

 クロージャは関数と無名で使える関数(クロージャ式)を包括したような概念です。Swiftの公式ガイドには「グローバル関数やネスト関数はクロージャの特別な場合(special cases of closures)である」と書かれています。

 クロージャの特徴の1つにキャプチャがあります。キャプチャとは、クロージャ外で宣言された定数、変数をクロージャ内部に取り込む仕組みです。例えば、関数内で宣言された定数や変数は、通常、関数の実行終了時に自動的に破棄されますが、クロージャにキャプチャされた定数や変数は、クロージャ自体が破棄されるまで値を保持し続けます。

 クロージャは、次の3つの形式でコード中に現れます。

●グローバル関数
 グローバル領域で宣言された一般的な関数です。ただし、定数、変数をキャプチャしません

●ネストされた関数
 関数の中で定義されるネスト関数は、定義されるコンテキストにある定数、変数をキャプチャします。

●クロージャ式
 クロージャを関数と比べて簡単な方式で書けるようにしたもので、関数の末尾に引数として多く現れます。呼び出されるコンテキストにある定数、変数をキャプチャします。

 Swiftの公式ガイドにおいて、コンテキストという用語は、コードの書かれるクロージャ・インスタンスメソッドからアクセス可能な範囲を示しています。関数内であれば、それが定義されたグローバル変数、定数、ローカル変数などが関数のコンテキストに含まれます。クラス内であれば、そのクラスのコンテキストは、他のクラスのメソッド内のローカル変数を含みません。

 関数が参照型のインスタンスとして扱えるのと同様に、クロージャ式も参照型のインスタンスとして扱えます。

 なお、クロージャにキャプチャされる定数、変数の種類によっては循環参照が引き起こされやすく、メモリリークの原因になります。そのため、キャプチャを避ける仕組みも用意されています(weak/unownedキーワード)。この仕組みを理解するには、クラス・ストラクチャの概要とオプショナル列挙型の知識が不可欠なので、解説は次回以降に行います。

クロージャ式

 クロージャ式は、次の一般的な形で記述できます。

{ (引数宣言) -> 返り値の型 in
    文
}

 クロージャ式は、Objective-Cにおけるblocksのように、関数の引数として記述することができます。次のコードは、Int -> Bool型の関数を引数として持つフィルタ関数filterNumsを宣言しています。フィルタ関数とは、値の集合と条件を受け取り、値の集合から条件に合致する値だけを集め、それを集合として返す関数のことです。

func filterNums(nums: [Int], cond: Int -> Bool) -> [Int] {
    var filteredNums: [Int] = []
    for num in nums {
        if cond(num) {
            filteredNums += num
        }
    }
    return filteredNums
}
func overTen(a: Int) -> Bool {
    return a > 10
}
filterNums([1,6,8,10,11,4,21], overTen) // [11, 21]

 overTenは引数が10より大きな値のときにtrueを返す関数で、フィルタ関数filterNumsに与えられる条件となっています。この条件はoverTen関数に代えて、クロージャ式にすることができます。

filterNums([1,6,8,10,11,4,21], {(a: Int) -> Bool in return a > 10})

 関数引数には型推論が行われるため、クロージャ式の引数の型宣言(:Int)と返り値の型宣言(-> Bool)は省くことができます。

filterNums([1,6,8,10,11,4,21], {a in return a > 10})

 inの後に続く文が1つである場合、returnキーワードは省略可能です。

filterNums([1,6,8,10,11,4,21], {a in a > 10})

 さらに、$0, $1,...で引数にアクセスする機構が備わっています。$0で1つ目の引数、$1で2つ目の引数にアクセスできます。この機構を使用する場合、引数の宣言とinも省けます。

filterNums([1,6,8,10,11,4,21], {$0 > 10})
 演算子に対しては、さらに省略できる記法がクロージャ式には備わっていますが、その解説は演算子を取り上げる回で行うことにします。

 引数の末尾にあるクロージャ式は、次のように末尾クロージャ式にする(引数のカッコの外に置く)ことも可能です。

filterNums([1,6,8,10,11,4,21]){$0 > 10}

次のページ
auto_closure属性

この記事は参考になりましたか?

  • X ポスト
  • このエントリーをはてなブックマークに追加
アップルの新プログラミング言語「Swift」を探検しよう連載記事一覧

もっと読む

この記事の著者

yad(ヤド)

クラスメソッド株式会社のアプリケーションエンジニア。iPhoneアプリケーションの開発に2年以上従事している。開発に使用するObjective-Cのみならず、関数型言語Haskellや機械学習などにも関心がある。「Developers.IO」に寄稿した記事の一覧

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

  • X ポスト
  • このエントリーをはてなブックマークに追加
CodeZine(コードジン)
https://codezine.jp/article/detail/7869 2014/07/09 21:05

おすすめ

アクセスランキング

アクセスランキング

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー

アクセスランキング

アクセスランキング