.doと.subscribeの違い(SwiftとC#から見た)

# .doと.subscribeの違い
気になった記事の該当部分のコピペ抜粋です　あとできっちりまとめる予定

#### ・[Rx時代の先にあるもの](https://blog.fenrir-inc.com/jp/2017/12/rx-earth.html)

**Rxの場合**

```do-swift.swift
incrementCount
    .do { increment in self.counter2 += increment } // 1
    .map { increment in increment * 2 } // 2
    .do { self.updateDatabase() } // 3
    .subscribe { newIncrement in // 4
        self.counter += newIncrement
    }
```
`do` 自分の外の状態（Counter2）を変更する分かりにくいクロージャ
`map` 引数の値を2倍にして返すだけ。それ以外に余計なこと(クロージャ外の状態変えたり)しない分かりやすいクロージャ
`do` データベースを操作しローカルの環境を大きく変える分かりにくいクロージャ
`subscribe` 自分の外の状態（Counter）を変更する分かりにくクロージャ
Rxでは登録したクロージャは分かりやすいもの、そうでないもの、明確な区別なく`Observer`に保持されます。また今回は`map`を分かりやすいクロージャにしましたが、
`map`内でスコープの広い状態の変更やデータベース操作などをすることで、分かりにくいクロージャにすることもできます。この辺は制約が無いため、Rxを使う人によってかなり幅がでます。

#### ・[Reactive Extensions再入門 その１０「Doメソッド」](https://blog.okazuki.jp/entry/20111128/1322491648)
**Doメソッド**
DoメソッドはIObservableから発行された値を受けて処理を行うだけのメソッドです。5.4.1のDrag処理でも使用しましたが、要素を受け取って処理を行いIObservableの要素に対しては何も加工を行ったりしません。コード例を下記に示します。

```do-c#.cs
var subject = new Subject<int>();
subject
    // 途中に処理を挟む
    .Do(i => Console.WriteLine("Do : {0}", i))
    // 購読(購読しないとOnNextをしても値が流れないね)
    .Subscribe(i => Console.WriteLine("OnNext : {0}", i));

// 値の発行
subject.OnNext(1);
subject.OnNext(2);
subject.OnNext(3);
```
このコードを実行すると、Subscribeで値を購読している処理の前にDoの処理が行われていることが確認出来ます。

```
Do : 1
OnNext : 1
Do : 2
OnNext : 2
Do : 3
OnNext : 3
```


#### ・[連載：Reactive Extensions（Rx）入門 |  第2回 イベント・プログラミングとRx](https://www.atmarkit.co.jp/fdotnet/introrx/introrx_02/introrx_02_01.html)
**IObserver<T>オブジェクトの詳細**
最初の「同じ実行結果のRxとforeach文のコード」の例ではIObserver<T>インターフェイスのメンバのうち、OnNextメソッドのデリゲートしか記述していなかった。このOnNextは、値がオブザーバに届くたびに実行されるメソッドで、最も利用されるものだろう。残りの2つのうち、OnErrorは例外発生時に実行されるメソッド、OnCompletedはシーケンスが完了後に実行されるメソッドを表す。これら3つのメソッドのデリゲートを指定する場合の、Subcribeメソッドのコード例を示す。 

```do-c#.cs
// 正常終了する場合 
// 実行結果：1, 2, 3, 4, 5, Completed 
Observable.Range(1, 5) 
   .Subscribe(
     x => Console.WriteLine(x), 
     ex => Console.WriteLine("Error"), 
     () => Console.WriteLine("Completed")); 

// 途中で例外が発生する場合 
// 実行結果：1, 2, Error 
Observable.Range(1, 5) 
   .Do(x => { if (x == 3) throw new Exception(); }) 
   .Subscribe( 
     x => Console.WriteLine(x), 
     ex => Console.WriteLine("Error"), 
     () => Console.WriteLine("Completed")); 
```

**do-vb.vb**

```vb

' 正常終了する場合 
' 実行結果：1, 2, 3, 4, 5, Completed 
 Observable.Range(1, 5). 
   Subscribe( 
     Sub(x) Console.WriteLine(x), 
     Sub(ex) Console.WriteLine("Error"), 
     Sub() Console.WriteLine("Completed")) 

 ' 途中で例外が発生する場合 
 ' 実行結果：1, 2, Error 
 Observable.Range(1, 5). 
   Do(Sub(x) 
       If (x = 3) Then 
         Throw New Exception() 
       End If 
     End Sub). 
   Subscribe( 
     Sub(x) Console.WriteLine(x), 
     Sub(ex) Console.WriteLine("Error"), 
     Sub() Console.WriteLine("Completed")) 
```
**OnError／OnCompletedメソッドのデリゲートを含めたSubcribeメソッドのコードの実行例（上：C#、下：VB）**
Doメソッドはパイプラインを通過する値に処理を加えて、元の値はそのまま後続へ渡す。今回は値が「3」のときに例外を発生させるようにした。 
上記のコードを実行した場合、Rangeメソッドにより「1」～「5」の値の生成が完了すると、OnCompletedメソッドが呼ばれる、もしくは途中で例外が発生するとOnErrorメソッドが呼ばれるのが確認できるだろう。なお、OnErrorメソッド、もしくはOnCompletedメソッドは、どちらか片方しか呼ばれることはない。つまり、OnErrorメソッドが呼ばれた後にOnCompletedメソッドが呼ばれたりすることはない。また、OnErrorメソッド、もしくはOnCompletedメソッドが呼ばれた後にOnNextメソッドが呼ばれることもない*3。

`*3　この法則はRxに標準で用意されているメソッドではすべて守られている。また、メソッドを自作する場合でもObservable.CreateメソッドといったRx標準で用意されている生成メソッドを用いれば守られる。さらにSubscirbeメソッドの呼び出し時にもRxで用意されているObserver（前述のSystem.ObservableExtensionsクラスによる拡張メソッド、もしくはObserver.Createメソッド）を使えば自動的に守られるようになっている。このように、幾重にも渡って法則が厳守されるようになっているため、ほぼ100％この法則が破られることはないが、IObservable<T>／IObserver<T>オブジェクトをすべて一から自前で実装する場合は、この法則に反する挙動をする可能性もある。ただし、そのような実装はすべきではない。安全のためにも、IObservable<T>インターフェイスやIObserver<T>インターフェイスを実装する際は、極力、Rxに用意されているObservable.Create／Observer.Createメソッドを利用して実装すべきだろう。どうしてもそれらが利用できない場合は、法則を守るように注意深く実装する必要がある。`