SwiftのOptionalと恋人以上の関係になりたい(その1)
はじめに
SwiftのOptional
について、こんな認識がありました。
Int?
はInt
が入るかもしれないしnil
が入るかもしれない型
これだけの認識でもSwiftのプログラミングは十分可能だと思います。
Optional Binding
やOptional Chaining
を使いこなせれば、Optionalと友達以上恋人未満の関係になったと言っていいでしょう。
ただ、それだけでは満足しきれない、もっとOptionalのことを知りたい!恋人以上の関係になりたい!と思うようになってきました。
Optionalの定義
Optionalの定義を確認してみます。(いろいろ省いています。
public enum Optional<Wrapped> { case None case Some(Wrapped) }
この時点でOptionalの認識が少し改まります。
Int?
はSome(Int)
が入るかもしれないしNone
が入るかもしれないOptional<Int>
という名の箱のようなもの
おお、nil
とかどこにも出てきませんね。。。
普段何気なく書いているコードを、enumを使ったコードっぽく書きなおしてみます。
let name: String? = "yukia" let age: Int? = nil ↓ let name: Optional<String> = .Some("yukia") let age: Optional<Int> = .None
こういう書き方もできるわけです。
let name: Optional<String> = String("yukia") let age: Optional<Int> = nil
これって普通じゃん、と思うかもしれませんが何気にすごい事です。
何がすごいかって、Optional<String>
にString
を代入しちゃってるってことです。Swiftは静的型付け言語なのででは暗黙的型変換は許されないし、Array<String>
にString
を代入するなんてことも普段考えませんよね?でもそれと同じことです。
なぜこのようなことが許されるのか、この一言に尽きると思います。
Optionalは例外として暗黙的型変換が許されている
おお、OptionalはSwiftでは特別扱いされているんですね!!!すごい!!!
Optional Binding
Optionalという箱から値を取り出して利用する方法の一つ、Optional Binding。
こちらも普段何気なく書いているコードと、enumを使ったコードとで比較してみましょう。
一般的な記述
let name: String? = "yukia" if let unwrapedName = name { print(unwrapedName) } else { print("unknown") }
if let ...
と書くことで、中の値を取り出していますね。取り出せない場合にはelse
に入ります。
これをenum的に記述すると以下のようになるでしょう。
let name: String? = "yukia" switch name { case .Some(let unwrapedName): print(unwrapedName) case .None: print("unknown") }
もちろんパターンマッチさせることも可能です。
Optional Chaining
それなりに使うことができていると自負していますが、もう少し掘り下げてみたいOptional Chaining。
まずはOptinal Chainingの基本的な動作を確認してみます。名前を大文字にしてかっこいい感じにしましょう。
Some(値あり)
let name: String? = "yukia" print(name?.uppercaseString) // 出力:Optional("YUKIA")
None(値なし)
let name: String? = nil print(name?.uppercaseString) // 出力:nil
nilならばnilを返すし、それ以外ならメソッドを適用して返しています。そういえばOptionalにはこんなメソッドが宣言されていました。
/// If `self == nil`, returns `nil`. Otherwise, returns `f(self!)`. @warn_unused_result @rethrows public func map<U>(@noescape f: (Wrapped) throws -> U) rethrows -> U? /// Returns `nil` if `self` is nil, `f(self!)` otherwise. @warn_unused_result @rethrows public func flatMap<U>(@noescape f: (Wrapped) throws -> U?) rethrows -> U?
map
flatMap
どちらでも似たようなことができるのですが、ここではflatMap
で説明します。
Optional Chaining挙動と似ていますね。そう、つまりは、Optional ChainingはflatMap
を用いて記述できるということです。
let name: String? = "yukia" let upperName = name.flatMap { $0.uppercaseString } print(upperName)
もっと長い複雑なOptional ChainingもflatMap
を使ってメソッドチェーンで記述することが可能です。
Optional Chainigは
flatMap
の構文糖衣である
といえるでしょう。
その1終わり
さて、この辺までくればOptionalのこともだいぶわかってきたと思います。恋人以上とは言えないが、好感度も上がり親密な関係になってきたことでしょう。
なんとなく漂ってくる雰囲気がHaskellのMaybe
に似ている、、と思いました。ただここは浮気せずにもうちょっとOptionalについて学んで行こうと思います。
次回はもっと踏み込んだところまで解説できればいいなと思います。