RustでResult<T, E>を返すイテレータに対し、トレイトを作って実装したら頭の体操だった話

*コメント欄でtermoshttさんに指摘いただいて、余分なSizedを省きました*

# Rustは厳しい
C++のテンプレートだと、「この型はイテレータだからな！」みたいなオレオレルールを、コンパイラに伝える必要はなく、どうがんばってもコンパイルできないことにコンパイラが気づいたらコンパイルエラーが出る、という、大変ゆるいルールで、事実上ダックタイピングみたいな感じなのですが。
Rustは、そのへんきっちりしてるので、ジェネリックが任意の型だと都合悪い場合には、そのことをコンパイラに伝えないといけないわけです。

分かりやすい例を出すと、以下のコードは

```rust
struct Foo<T> { foo: T }
impl<T> Foo<T> {
    fn func(self, other: Foo<T>) -> T { self.foo + other.foo }
}
```

「Tって足し算できるの？　そんなの聞いてない！」ってエラーになります。

```
error[E0369]: binary operation `+` cannot be applied to type `T`
```

コンパイラには「この実装は、Tが足し算できるときの実装なんですよ」と教えないといけません。

```rust
use std::ops::Add;
struct Foo<T> { foo: T }
impl<T> Foo<T> where T: Add {
    fn func(self, other: Foo<T>) -> T { self.foo + other.foo }
}
```

じゃあ今度は「え？　TとTを足し算したらTになるんだっけ？　Add::Output 型になるんじゃなかった？」ってエラーが出ます。
これに対処する方法は2つあって。ひとつは、funcの戻り値の型を Add::Output 型にする方法。

```rust
use std::ops::Add;
struct Foo<T> { foo: T }
impl<T> Foo<T> where T: Add {
    fn func(self, other: Foo<T>) -> <T as Add>::Output { self.foo + other.foo }
}
```

もうひとつは「この実装は、Tが足し算できて、OutputがTの場合の実装なんですよ」とコンパイラに教える方法。

```rust
use std::ops::Add;
struct Foo<T> { foo: T }
impl<T> Foo<T> where T: Add<Output=T> {
    fn func(self, other: Foo<T>) -> T { self.foo + other.foo }
}
```

どちらがいいかは、Fooがどうあってほしいかに依ります。Tが返ってこないと都合が悪い場合は、後者の方がいいでしょうし、Tが返ってこなくても何か返ってきたらいい場合は前者の方がいいでしょう。

# トレイトを作ろう
さて。前置きが長くなりましたが。
`Result`が返ってくるイテレータ、なる鬱陶しいものがあったので。これを片っ端から`unwrap()`して返すイテレータと、それを返すトレイトをイテレータに対し実装しようとしました。

やりたいことは、大体、以下のような感じです。
これに、つけなければいけない制約は仕方なくつけながら、コンパイルできるようにしよう、というお話です。

```rust
// コンパイルできないよ！
pub trait ResultIter {
    fn unwrap(self) -> Unwrap<Self> {
        Unwrap { iter: self }
    }
}
impl ResultIter for Iterator {}

pub struct Unwrap<I> {
    iter: I,
}
impl<I> Iterator for Unwrap<I> {
    fn next(&mut self) -> Option<Self::Item> {
        self.iter.next().map(|e| e.unwrap())
    }
}
```

# 苦難のはじまり
まず怒られたのが `impl ResultIter for Iterator {}` の `Iterator`ってのはダメだ、と。何を返すイテレータか、Itemを示せ、と怒られました。`Result<T, E>`のイテレータだとコンパイラに教えましょう。

```rust
pub trait ResultIter<T, E> {
    fn unwrap(self) -> Unwrap<Self> {
        Unwrap { iter: self }
    }
}
impl<T, E> ResultIter<T, E> for Iterator<Item=Result<T, E>> {}
```

# Sizedとの戦い
続いて怒られたのが、`ResultIter<T, E>`が、`Sized`じゃない、と怒られました。
`Sized`は、暗黙のうちに型パラメータにつけられるトレイトで、`Unwrap<I>`型の`I`には、暗黙のうちに以下のように`Sized`が要求されているので怒られました。

```rust
pub struct Unwrap<I: Sized> {
    iter: I,
}
```

そこで、

```rust
pub struct Unwrap<I: ?Sized> {
    iter: I,
}
```

のように `?Sized` にすれば、`Sized`でも`Sized`じゃなくてもどちらでもよくなるのですが、
Rustでは、関数の引数と戻り値は`Sized`である必要があるので、
`ResultIter<T, E>` の中の `fn unwrap(self) -> Unwrap<Self>` は、`self` も `Unwrap<Self>`もどちらも`Sized`じゃないとマズいよなーってことがわかります。
仕方ないので、`ResultIter`も`Unwrap`も`Self: Sized`を要求することにします。

```rust
pub trait ResultIter<T, E> where Self: Sized {
    fn unwrap(self) -> Unwrap<Self> {
        Unwrap { iter: self }
    }
}
impl<T, E> ResultIter<T, E> for Iterator<Item=Result<T, E>> {}

pub struct Unwrap<I: ?Sized> {
    iter: I,
}
impl<I> Iterator for Unwrap<I> where Self: Sized {
    fn next(&mut self) -> Option<Self::Item> {
        self.iter.next().map(|e| e.unwrap())
    }
}
```

すると、面白いコンパイルエラーが出ました。

```
error[E0277]: the trait bound `std::iter::Iterator<Item=std::result::Result<T, E>> + 'static: std::marker::Sized` is not satisfied
```

「いやいや、そもそも`Iterator<Item=Result<T, E>>`って、Sizedじゃないんだけど。それがSizedってどういうことよ？」……とのことです。
Sizedって何？という話は[ここ](http://qnighy.hatenablog.com/entry/2017/03/04/131311)に詳しく書いてあります。

ならばこれでどうじゃ！　(これ思いつくのに2日くらいかかりました。こんなんアリだったんですね)

```rust
pub trait ResultIter<T, E>: Sized {
    fn unwrap(self) -> Unwrap<Self> {
        Unwrap { iter: self }
    }
}
impl<I, T, E> ResultIter<T, E> for I where I: Iterator<Item=Result<T, E>> {}
```

# 幽霊を呼び出せ
続いて怒られるのは、`impl<I> Iterator for Unwrap<I>`の方で。「`Iterator`の実装するなら`type Item`を定義しないといけないんだけど、見当たらない」です。
じゃあ`type Item = T`を作れば・・・・って、Tがない！
さらには、`Iterator`が`Iterator<Item=Result<T, E>>`だということも教えとかないと怒られそう。

なければつければいい。
`impl<I, T, E> Iterator for Unwrap<I> where Self: Sized`

そしたら、もちろん怒られる。「Tってなに？ Eってなに？ そんなん急に言われても分からん」

```
error[E0207]: the type parameter `T` is not constrained by the impl trait, self type, or predicates
error[E0207]: the type parameter `E` is not constrained by the impl trait, self type, or predicates
```

ならばUnwrap型に持たせよう。

```rust
pub struct Unwrap<I, T, E> {
    iter: I,
}
```

怒られました。「T使ってないじゃん！　E使ってないじゃん！」

```
error[E0392]: parameter `T` is never used
error[E0392]: parameter `E` is never used
```

なので、無理矢理TとEを使わないといけないわけです。
とはいえ、無駄な変数持ちたくないし、そもそもTとEをどう初期化したらいいかも分かりません。
そこで出てくるのが、無駄な型パラメータを消費するための[PhantomData](https://doc.rust-lang.org/std/marker/struct.PhantomData.html)です。

```rust
use std::marker::PhantomData;
pub trait ResultIter<T, E>: Sized {
    fn unwrap(self) -> Unwrap<Self, T, E> {
        Unwrap { iter: self, phantom: PhantomData }
    }
}
impl<I, T, E> ResultIter<T, E> for I where I: Iterator<Item=Result<T, E>> {}

pub struct Unwrap<I, T, E> {
    iter: I,
    phantom: PhantomData<*const (T, E)>,
}
impl<I, T, E> Iterator for Unwrap<I, T, E> where I: Iterator<Item=Result<T, E>> {
    type Item = T;
    fn next(&mut self) -> Option<Self::Item> {
        self.iter.next().map(|e| e.unwrap())
    }
}
```

`PhantomData<*const (T, E)>`については、公式ドキュメント内に、PhantomDataの型パラメータを参照やポインタにしなかったら、型が中身を所有しているものとみなされてDrop checkがされるので、所有してないときは参照やポインタにしようね、とあったので、そうしてみました。(正直よく分かってません)

# 戦いの終わり
まだエラーが出ます。実は`Result<T, E>::unwrap()`は、`E`に`Debug`が実装されてないと使えないらしいです。そんなのしらなかった！
どうすりゃいいか、もう簡単ですよね。

```rust
use std::fmt::Debug;
use std::marker::PhantomData;
pub trait ResultIter<T, E>: Sized {
    fn unwrap(self) -> Unwrap<Self, T, E> {
        Unwrap { iter: self, phantom: PhantomData }
    }
}
impl<I, T, E> ResultIter<T, E> for I where I: Iterator<Item=Result<T, E>> {}

pub struct Unwrap<I, T, E> {
    iter: I,
    phantom: PhantomData<*const (T, E)>,
}
impl<I, T, E: Debug> Iterator for Unwrap<I, T, E> where I: Iterator<Item=Result<T, E>> {
    type Item = T;
    fn next(&mut self) -> Option<Self::Item> {
        self.iter.next().map(|e| e.unwrap())
    }
}

fn main() {
    let v: Vec<Result<i32, i32>> = vec![Ok(1), Ok(2), Ok(3)];
    assert_eq!(v.into_iter().unwrap().collect::<Vec<_>>(), vec![1, 2, 3])
}
```

無事、コンパイルが通り、エラーなく実行できました。

# さいごに
Rustはコンパイラがきっちりしている、良い言語ですが、あまりにきっちりしすぎていて、コンパイルエラーとの戦いは試練です。(それでも多くの場合、きれいな解決法があるので、パズルの解き甲斐はあります)
まだ新しい言語で、特に日本語では情報が少ないので、多くの情報を書き散らかしながら、ググればHOWTOがすぐに見つかる状態にしたいなぁ、という気持ちもあります。

実は今回のトレイトの、もう少しいろんな機能つけたのを、[GitHub](https://github.com/gyu-don/options_results)や[Crates.io](https://crates.io/crates/options_results)で公開しています。
が、[最初に書いたコード](
https://github.com/gyu-don/options_results/blob/abaa40ee13e0e4f0dc869a712b4a17bc5bca162b/src/resultiter.rs)は、それはそれは、ひどいものでした。
いろいろと戦って、
`pub trait ResultIter: Iterator where Self: Sized, <Self as Iterator>::Item: Result<T, E>`
とすると、「トレイトがくるはずのところにEnumがきてる！おかしい！」と怒られ、苦し紛れに無理矢理トレイトを作ったら、闇が闇を呼ぶコードになりました。

なんとかならんのか、ともう一度考えてみたら、かなりきれいにパズルがとけて、嬉しくなって記事を書いてみた次第です。
嬉しい、楽しいはエンジニアの原動力の一つなので。そういう純粋な喜びから、良いプログラムや良い記事がいっぱい書けたらいいなぁ、と思う次第です。