2019/12/13 Swift クロージャー パート1(基本)

クロージャの定義方法

クロージャの定義方法(基本)
{(引数名1 : 型名 , 引数名2 : 型名) ->戻り値の型 in //クロージャの実行内容 //return 戻り値の式 }

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"]

 

 

 

 

コメントを残す

メールアドレスが公開されることはありません。