処理をまとめる[関数・クロージャ]
関数
func 関数名 ( パラメタ ) -> 戻り値の型 { 処理内容 }
func doubleVal(val: Int) -> Int { return val * 2 }
- パラメタ・戻り値なし
// パラメタ無し func sayHello() { println("Hello") } // 戻り値無し func sayHello() -> Void { println("Hello") }
- 複数のパラメタ・戻り値
// 複数のパラメタ func multiply(val1: Int, val2: Int) -> Int { return val1 * val2 } // 戻り値のタプル仕様 func httpRequest(url: String) -> (Int, String) { return (404, "Not Found") } let (code, message) = httpRequest() code // 404 message // "Not Found"
- パラメタ外部名
func joinPieces(arr: [String], withGlue glue: String) -> String { return glue.join(arr) } joinPieces(["a","b","c"], withGlue: ":") // "a:b:c"
- 外部名と内部名が等しい
func joinPieces(arr: [String], #withGlu: String) -> String { return glue.join(arr) } joinPieces(["a","b","c"], withGlue: ":") // "a:b:c"
パラメタ・外部名が違えば別関数
関数名では特定できない
外部名を持たない第一パラメタについては「」記号で表現
joinPieces(_: withGlue: )
- パラメタのデフォルト値
func joinPieces(arr: [String], withGlue glue: String = ":") -> String { return glue.join(arr) } joinPieces(["a","b","c"]) // "a:b:c"
- デフォルト値と外部名
// デフォルト有り func joinPieces1(arr: [String], glue: String = ":") -> String { return glue.join(arr) } // デフォルト無し func joinPieces2(arr: [String], glue: String) -> String { return glue.join(arr) } // 外部名が必要 joinPieces1(["a","b","c"], glue: ":") // "a:b:c" // 外部名が不要 joinPieces2(["a","b","c"], ":") // "a:b:c"
- 可変数パラメタ
func sum(mumbers: Int...) -> Int { var sum = 0 for mum in mumbers { sum += mum } return sum } sum(1,2,3,4,5) // 15
- パラメタの変更と参照
// 関数内での定数と変数 func repeatFrom(var from: Int, #to: Int) { // formにvarをつけて変数定義 do { println("\(from)") // 5 6 7 8 9 10 } while ++from <= to // formのインクリメント } var from = 5 repeatFrom(from to:10) from // 5 // 元の値は維持
- inoutパラメタ
func swap(inout a: Int, inout b: Int) { let temp = a a = b b = temp } var a = 1 var b = 2 swap(&a, &b) // 参照渡し a // 2 b // 1
- 関数型 / すべての関数は「関数型」を持つ
// 同一の関数型 func add(a: Int, b: Int) -> Int { return a + b } func multiply(a: Int, b: Int) -> Int { return a * b }
これはどちらも
(Int, Int) -> Int
という関数型を持っている
- 関数型の定義
// 「(Int, Int) -> Int」型の変数calcFuncを定義してaddを初期値として設定 var calcFunc: (Int, Int) -> Int = add calcFunc(1, 2) // 3
- 関数型を使用した関数
func zero(a: Int, b: Int) -> Int { return 0 } // 戻り値「(Int, Int) -> Int」を返す func getCalcFunc(name: String) -> (Int, Int) -> Int { switch name { case "add": return add case "multiply": return multiply default: return zero } } // 戻り値が関数なのでそのままパラメタを渡す getCalcFunc("add")(3, 4) // 7 getCalcFunc("multiply")(3, 4) // 12
クロージャ / 名前を持たない関数
{( パラメタ ) -> 戻り値 in 処理内容 }
- 実装例
{(a: Int, b: Int) -> Bool in return a < b }
「(Int, Int) -> Bool」の型をもつ値
- 定義済の関数を使用したsorted関数の使用
func compare(a: Int, b: Int) -> Bool { return a < b } var arr = [3, 5, 1, 2, 4] sorted(arr, compare) // [1, 2, 3, 4, 5]
- クロージャを使用して書き換え
var arr = [3, 5, 1, 2, 4] sorted(arr, { (a: Int, b:int) -> Bool in return a < b }) // [1, 2, 3, 4, 5]
- 型推測
var someFunc: (Int, Int) -> Bool //パラメタ・戻り値の型省略 someFunc = { a, b in return a < b }
- sorted関数が型を決めてる
var arr = [3, 5, 1, 2, 4] sorted(arr, { a, b in return a < b })
- パラメタ表記 / 戻り値の省略
var arr = [3, 5, 1, 2, 4] // 元の形 sorted(arr, { (a: Int, b: Int) -> Bool in return a < b }) // 型推測による省略形 sorted(arr, { a, b in return a < b }) // パラメタの省略形 sorted(arr, { return $0 < $1 }) // returnの省略形 sorted(arr, { $0 < $1 })
「<」演算子は「(Int, Int) -> Bool」の型を持っているので・・・
var arr = [3, 5, 1, 2, 4] sorted(arr, <)
とも書ける・・・。Σ(゚д゚;)えー! ちょっと感動。 こういう考え方に早く出会いたかったなぁ。
- トレイリングクロージャ
var arr = [3, 5, 1, 2, 4] sorted(arr){$0 < $1}
クロージャが関数の最後のパラメタになるときこう記述可
- 1つのパラメタのトレイリングクロージャ
var arr = [3, 5, 1, 2, 4] // 通常の記述 arr.map({ (mumber: Int) -> String in return "(\(mumber))" }) // トレイリングクロージャ arr.map{ (mumber: Int) -> String in return "(\(mumber))" } // 関数のパラメタを表す( )の省略パターン
むむっ。ややこしい。
値のキャプチャ
func makeProgressBar(mark: String) -> ( ) -> String { var bar = "" func progressBar( ) -> String { bar += mark return bar } return progressBar } // progressBar( )が、定数markや変数barをキャプチャしている状態 // 関数のネストと関数を返す関数 var plusProgressBar = makeProgressBar("+") plusProgressBar( ) // "+" plusProgressBar( ) // "++" plusProgressBar( ) // "+++"
注意キーワード):循環参照
まとめ
クロージャは多様な省略ルールを知らないとコード読めない。 順をおってひとつずつ。