クロージャの定義方法
sample1
let triple={(x:Int)->Int in return x*3 } print(triple(300)) //900
returnキーワードの後に戻り値の式を記述するのが基本だが、クロージャ内の文が1つの場合returnキーワードは省略可能。上記のsample1は次のように書き換え可能。
sample1-1
let triple={(x:Int)->Int in x*3 //文が1つしかないのでreturnを省略できる。 } print(triple(300)) //900
returnを省略できるのはクロージャのブロック内({}の中)の文が1つの場合のみ。文が2つ以上でreturnを省略するとエラーが出るので注意。
引数の型をクロージャ型として宣言する(型注釈)場合
クロージャの型は
で表現する。
sample2
let triple:(Int)->Int ={(x:Int)->Int in return x*3 } print(triple(500))
上記sample2では定数tripleの型注釈として(Int)->Int型(クロージャ型)としている。
sample3
let triple:(Int)->Int={(x:Int)->Int in return x*3 } func exfunc(clo:(Int)->Int)->Int{ let y=50 return clo(y) } print(exfunc(clo:triple)) //150
上記sample3では、exfunc関数の引数cloの型注釈として(Int)->Int(クロージャ型)としている。
exfunc関数の戻り値の型はInt型。
型推論(クロージャの型宣言を省略できる場合)
変数にクロージャを代入するとき。
=(代入演算子)の左辺で型注釈する。
=(代入演算子)の右辺のクロージャ内で、クロージャの引数の型・戻り値の型を宣言する。
左右両方型を示して、左右の型が一致すれば当然代入できる(sample4)
sample4
var clo:(String)->Int clo={(str:String)->Int in return str.count } let str1="ab" let str2="weweee" let str3="aaaaaaaaaaafff" print(clo(str1)) print(clo(str2)) print(clo(str3)) //2 //6 //14
変数cloの宣言時に型注釈(アノテーション)をしていれば、クロージャの定義の中での引数の型・戻り値の型を省略できる。(sample5)
sample5
var clo:(String)->Int clo={str in //←引数の型・戻り値の型を省略できる return str.count } let str1="abc" let str2="weweeeaa" let str3="aaaaaaaaaaa" print(clo(str1)) print(clo(str2)) print(clo(str3)) //3 //8 //11
clo={(str:String)->Int in //←赤い部分は省略できる。
return str.count
}
↓
clo={str in
str.count
}
sample5では変数cloの宣言時(1行目)に(String)->Int型である、と型注釈しているので、3行目で代入するクロージャーの型は(String)->Int型であるとSwiftが型推定できます。
従って3行目以下のクロージャーの定義内では、「クロージャーの引数の型(String型)」と「クロージャーの戻り値の型(Bool型)」は省略できます。
さらにクロージャーの全ての引数と戻り値の型がわかっている場合、クロージャーの引数を囲む丸かっことアロー( -> )も省略できます。よって変数cloに代入するクロージャーはsample5のように書きことができます。
sample6-1
//https://docs.swift.org/swift-book/LanguageGuide/Closures.html let names = ["Chris", "Alex", "Ewa", "Barry", "Daniella"] var reversedNames = names.sorted(by: { (s1: String, s2: String) -> Bool in return s1 > s2 } ) print(reversedNames) //["Ewa", "Daniella", "Chris", "Barry", "Alex"]
sample6-1は
https://docs.swift.org/swift-book/LanguageGuide/Closures.html
で示されているサンプルコードです。Array型のメソッドsortedの引数として渡されているクロージャーは引数・戻り値の型が記述されています。もちろんこの記述方法でも全く問題ないのですが、sortedメソッドは、
引数は配列の要素の型、戻り値はBool型
と標準ライブラリ内で定義されていますので、sortedメソッドに渡されるクロージャー内での型注釈を省略することができます。省略したコードがsample6-2です。
sample6-2
let names = ["Chris", "Alex", "Ewa", "Barry", "Daniella"] var reversedNames = names.sorted(by: { s1, s2 in return s1 > s2 } ) print(reversedNames) //["Ewa", "Daniella", "Chris", "Barry", "Alex"]
sample6-1と同様に問題なく動作していることがわかります。
クロージャーの本体が1行のクロージャーは、戻り値を返す時にreturnキーワードを省略できます。これをImplicit Return(暗黙的戻り値)と言います。
Implicit Returnを使うとsample6-2は以下(sample7)のように書けます。
sample7
let names = ["Ochris", "Yalex", "Ewa", "Varry", "Daniella"] var reversedNames = names.sorted(by: { s1, s2 in s1 > s2 } ) print(reversedNames) //["Yalex", "Varry", "Ochris", "Ewa", "Daniella"]
クロージャーの引数の型がわかっている場合sample7のように省略できるわけですが、この状況を前提としてさらに引数名(sample7ではs1,s2)の宣言も簡略化することができます(shorthand argument names、略式引数名)。さらにinキーワードも省略できます。
var reversedNames = names.sorted(by: { s1, s2 in s1 > s2 } )
↑赤文字部分は省略して、略式引数名を使うことができる。
s1→$0
s2→$1
略式引数名はクロージャーの引数を先頭から$0,$1,$2,…のように自動的に用意されます。sample7を略式引数名を用いて書き直すとsample8のようになります。
sample8
let names = ["Ochris", "Yalex", "Ewa", "Varry", "Daniella"] var reversedNames = names.sorted(by: { $0 > $1 } ) print(reversedNames) //["Yalex", "Varry", "Ochris", "Ewa", "Daniella"]