Observableをnilでフィルタしてアンラップする

RxSwiftでOptionalの値を扱うとき、nilでない場合のみ処理をしたいことがあります。
この記事では、nilをフィルタし値をアンラップして使う（ストリームに流す）方法を記載します。

[**方法1 filter と map**](http://qiita.com/ryotapoi/items/925a74ed4df9cb351c32#方法1)
[**方法2 flatMap**](http://qiita.com/ryotapoi/items/925a74ed4df9cb351c32#方法2)
[**方法3 unwrapを自作する**](http://qiita.com/ryotapoi/items/925a74ed4df9cb351c32#方法3)


追記:
[コメント](http://qiita.com/ryotapoi/items/925a74ed4df9cb351c32#comment-d67c809dafd360f2786d)で @su_k さんから [**RxOptional**](https://github.com/RxSwiftCommunity/RxOptional) を教えていただきました！　Optional関連の高機能な拡張ですね。
また[追加情報](http://qiita.com/ryotapoi/items/925a74ed4df9cb351c32#comment-8a4082ceda1ff4c7cad2)を @mono0926 さんからいただきました！



## 方法1

```swift
let observable = PublishSubject<String?>()

observable
    .filter { $0 != nil }
    .map { $0! }

```

filterでnilを取り除きます。

filterは条件でフィルタするだけで、型は`String?`のままです。それをmapで強制的にアンラップします。
ビックリ`!`するのが嫌な感じですが、短く読みやすいです。


## 方法2

```swift
observable
    .flatMap { string -> Observable<String> in
        if let string = string {
            return Observable.just(string)
        } else {
            return Observable.empty()
        }
}
```

RxSwiftのflatMapを使う方法です。flatMapの引数のクロージャはObservableを返すようにします。

クロージャが返したObservableが空っぽなら値は流れません。つまりフィルタされます。
Observableに値をひとつ入れると、値がひとつ流れていきます。
（ここでは使いませんが、Observableに複数の値を入れると複数の値が流れていきます。）

nilの場合は空`Observable.empty()`を返すことでフィルタされます。
値がある場合は`if let`で取り出した`String`を`Observable.just()`に入れることで、`String?`ではなく`String`が流れていきます。

OptionalのflatMapも使うと短く書けます。

```swift
observable
    .flatMap { $0.flatMap { Observable.just($0) } ?? Observable.empty() }
```

もしくは

```swift
observable
    .flatMap { $0.flatMap(Observable.just) ?? Observable.empty() }
```

通常はこの書き方がおすすめです。
`if let`の書き方は戻り値の型を指定しないとコンパイルできず冗長になりがちです。（returnがふたつあると型推論してくれない？🤔）


## 方法3

```swift
protocol Optionable {
    associatedtype Wrapped
    func flatMap<U>(_ transform: (Wrapped) throws -> U?) rethrows -> U?
}

extension Optional: Optionable {}

extension ObservableType {
    func unwrap<R: Optionable>(_ transform: @escaping ((E) -> R)) -> Observable<R.Wrapped> {
        return flatMap { (element: E) -> Observable<R.Wrapped> in
            transform(element).flatMap(Observable.just) ?? Observable.empty()
        }
    }
}

observable
    .unwrap { $0 }
```

方法1,2では標準の機能を使いました。方法3はObservableを拡張しunwrapを追加します。

使い方はunwrapの引数にOptionalを返すクロージャを渡すだけ。nilを返せばフィルタされ、値があれば流れていきます。上記例では`$0`が`String?`なので単純に`$0`を返しています。
nilになるかもしれない式を書き、map + nilのフィルタ + アンラップのようにも使えます

```swift
observable
    .unwrap { $0 } // ここを通るとStringになる
    .unwrap { Int($0) } // StringをIntに変換できた場合のみ、Intが流れていく
```

`{ $0 }` を書くのもめんどくさい、という場合は以下も組み合わせると幸せになれます😃

```swift
func identify<A>(_ id: A) -> A {
    return id
}

extension ObservableType where E: Optionable {
    func unwrap() -> Observable<E.Wrapped> {
        return unwrap(identify)
    }
}

observable
    .unwrap()
```

nilをフィルタすることが多い場合、unwrapを追加する方法もおすすめです。


### 補足

RxSwiftの`Observable`は`ObservableType`を実装しているのでそれを拡張しています。`ObservableType`の値の型は`E`と定義されています。

unwrapでやりたいことは以下の通りです。

1. クロージャを引数で受け取る
1. `値: E` をクロージャへ渡し、クロージャからOptionalの何かを受け取る
1. nilならフィルタし、値があればアンラップして流す

残念ながら「Optionalの何か」を `R?` `Optional<R>` `R = Optional` のようには書けません。書けたら楽そうなのに😑

unwrapで使いたいOptionalの機能（定義）は以下のふたつです

```swift
associatedtype Wrapped
func flatMap<U>(_ transform: (Wrapped) throws -> U?) rethrows -> U?
```

これをプロトコル`Optionable`として定義し、Optionalはそれを実装していると宣言します。

`unwrap(_:)`はクロージャの戻り値が`Optionable`であるとして処理を書いています。
`unwrap()`はEが`Optionable`であるとして処理を書いています。

`identify(_:)`を定義しているのは趣味です😃
もちろん`{ $0 }`で問題ありません。