mapを学ぶ
さて、少しずつSwiftにも触れていきます。
巷では「Swiftなら関数型プログラミングだよ」「map/flatMapはSwiftのたしなみ」のようなことが言われていて、実際のところ有名どころのライブラリは、こうした考え方を活用して作られています。ですが、正直なところ私はこれらを理解しているとはいえない状況なので、まずはこのmap,flatMap辺りから学んでいこうと思います。
■ map()
オンラインマニュアルのmap()
に関する記述を調べてみると、いくつかの型でメソッドとして用意されていて、それぞれ次のように書かれています。
Optional, ImplicitlyUnwrappedOptional
/* If self == nil, returns nil. Otherwise, returns f(self!). */ public func map<U>(@noescape f: (T) -> U) -> U? // Optional public func map<U>(@noescape f: (T) -> U) -> U! // ImplicitlyUnwrappedOptional
説明にある「もしself == nil
の場合はnil
を返し、そうでなければf(self!)
の結果を返す」ということは、たとえばOptional Bindingを使って書く以下の処理:
let transformed: String? if let foo = optionalfoo { transformed = String(foo) } else { transformed = nil }
は、map()
を使えば次のようにもっとシンプルに書けるということですね(極端な例ですが…)。ふむふむ。
let transformed = optionalfoo.map{ String($0) }
あ、書いていて気づいたのですが、このtransformed
の型はOptional型のままで、処理の前後で変数のOptional性(とでもいうのかな)は変化しないです。定義にあるようにOptional
のmap()はU?
を返し、ImplicitlyUnwrappedOptional
のmapもU!
を返しています。nil
の場合はnil
を返すので当然なのですが、ImplicitlyUnwrappedOptional
もそのまま同じで扱えるようになっているのは面白いです。
CollectionType, SequenceType
次はコレクション/シーケンス型です。コレクションに対してT
の配列を返します。
swift public func map<T>(@noescape transform: (Self.Generator.Element) -> T) -> [T]
Return an Array containing the results of mapping transform over self.
transform
引数がT
単体を返すことを求めていることから、結果の要素数は元のコレクションの要素数と同じになるようです。本当にそうかなと試してみると、
(0...3).map{ i -> [String] in [String(i)] } // [["0"], ["1"], ["2"], ["3"]] (0...3).map{ i -> String? in if i%2 == 0 { return String(i) } else { return nil } } // [{Some "0"}, nil, {Some "2"}, nil]
ということで、やはり同じ要素数になります。
LazyBidirectionalCollection, LazyForwardCollection, LazyRandomAccessCollection, LazySequence
map
メソッドを持っている型の最後は、「Lazy〜」と名付けられた遅延評価型のコレクションです。
/* Return a MapCollection over this LazyBidirectionalCollection / LazyForwardCollection / LazyRandomAccessCollection / LazySequence. The elements of the result are computed lazily, each time they are read, by calling transform function on a base element. */ public func map<U>(transform: (Base.Generator. Element) -> U) -> XXX <MapCollection <Base, U>>
基本は先ほどのコレクション/シーケンス型と同じですが、こちらは曰く「この(Lazyなコレクション/シーケンス型)を通じてMapCollection型を返す。結果の各要素は、実際に読まれる段階になってはじめて変換関数が呼ばれ、計算される」とあります。遅延評価型のコレクション/シーケンス型の1つ1つに対して処理を行うものの、実際に評価されるのは結果の配列にアクセスした時になるということですか。なるほど。