rustのimpl分岐テクニック


（雑な導入）
rust、なんか`trait`をちょっと賢く`impl`しようとすると衝突しがちです。　でもあきらめないで！　場合によっては回避できるかもしれません。

# 問題

ある商品をお買い物にいく`trait`、`GoToBuy`なるものをこんな感じで定義します：

```rust
trait GoToBuy {
    fn go_to_buy();
}
```

買う商品は、こんな感じでいくつか定義しましょうか：

```rust
struct Apple;    // りんご
struct Banana;   // ばなな
struct Cherries; // さくらんぼ
struct Cat;      // ねこ
struct Dog;      // いぬ
```

いちいち各商品ごとに`GoToBuy`を実装してもいいのですが、果物は果物屋さんに、動物はペット屋さんに行くという共通点があるので、実装をまとめたいですよね。 果物と動物の`trait`を定義してやりましょう：

```rust
trait FruitTrait {}
impl FruitTrait for Apple {}
impl FruitTrait for Banana {}
impl FruitTrait for Cherries {}

trait AnimalTrait {}
impl AnimalTrait for Cat {}
impl AnimalTrait for Dog {}
```

そして、それぞれの`trait`ごとに`GoToBuy`を定義してやれば完璧ですね：

```rust
impl<T: FruitTrait> GoToBuy for T {
    fn go_to_buy() {
        println!("果物屋さんにGo!");
    }
}

impl<T: AnimalTrait> GoToBuy for T {
    fn go_to_buy() {
        println!("ペット屋さんにGo!");
    }
}
```

しかし残念ながら、これは通りません：

```
error[E0119]: conflicting implementations of trait `GoToBuy`
  --> src\main.rs:26:1
   |
20 | impl<T: FruitTrait> GoToBuy for T {
   | ----------------------------- first implementation here
...
26 | impl<T: AnimalTrait> GoToBuy for T {
   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation

For more information about this error, try `rustc --explain E0119`.
```

実装が衝突していると怒られてしまいます。 フルーツと動物なんだから衝突してないだろという気もしますが、未来の世界で[フルーツ獣](https://www.google.com/search?q=%E3%83%95%E3%83%AB%E3%83%BC%E3%83%84+%E5%8B%95%E7%89%A9&tbm=isch)とかが登場したら衝突してしまうので、仕方ないですね。 もうちょっと真面目に書くと、コンパイラ側からは`FruitTrait`と`AnimalTrait`が同時に実装されている型が存在しえないことがわからないので、このように怒られてしまっています。

でも仕方ないで済ませたくないじゃないですか。 今回はアホみたいな1行`impl`だからいいですが、もしかしたら100行ある巨大`impl`かもしれないですし、フルーツと動物がそれぞれ100種類いるかもしれません。 フルーツ獣は登場しないという前提の下で、これをなんとか実装できないでしょうか？ というのが今回の問題です。

ちなみに、どんな組み合わせだと衝突すると判定され、どんな組み合わせだと衝突しないかは[RFC 1210](https://rust-lang.github.io/rfcs/1210-impl-specialization.html#what-is-overlap)に詳細な例が載っています。 暇なときにでも読んでみてください。

# 解決策その1：型をいじる

さっきの例だと、どっちも`impl ... for T`と、型`T`に対して`impl`をしていました。 `T`はなんでもあり型なので、うかつに`impl`対象に使うと衝突しがちです。 代わりに、こんな感じにしてみてはどうでしょうか：

```rust
struct Fruit<T>(T);
struct Animal<T>(T);

struct AppleTag;
struct BananaTag;
struct CherriesTag;
struct CatTag;
struct DogTag;

type Apple = Fruit<AppleTag>;
type Banana = Fruit<BananaTag>;
type Cherries = Fruit<CherriesTag>;
type Cat = Animal<CatTag>;
type Dog = Animal<DogTag>;

impl<T> GoToBuy for Fruit<T> {
    fn go_to_buy() {
        println!("果物屋さんにGo!");
    }
}

impl<T> GoToBuy for Animal<T> {
    fn go_to_buy() {
        println!("ペット屋さんにGo!");
    }
}
```

こうすれば、ふたつの`impl`は互いに違う型、`Fruit<T>`と`Animal<T>`に対して行っているので、衝突のしようがなくなりコンパイルが通るようになります。 やったね。
この方法の問題は、もちろん`Apple`や`Cat`などの型をいじる必要があったことです。 このケースではこれらの型は何もデータを持っていないハリボテなので好き勝手できましたが、他crateから持ってきた型だったり中身がある型だったりするとなかなかいじるのは難しいことがあります。 運がよければここで言う`Fruit`/`Animal`の型に`Deref`/`DerefMut`を実装するだけでなんとかなることもありますが、そうでないケースも多々あります。

# 解決策その2: `trait`をもう一段かます

こんどは型ではなく`trait`の側をいじるアイディアです。 いったんさっきの解決策のコードは忘れて、また一から`GoToBuy`と各種フルーツ動物を定義します：

```rust
trait GoToBuy {
    fn go_to_buy();
}

struct Apple;
struct Banana;
struct Cherries;
struct Cat;
struct Dog;
```

そして、`FruitTag`と`AnimalTag`という型を定義します。 名前にTagとついている通り、これらの型はただの印であって中身はなにもありません：

```rust
struct FruitTag;
struct AnimalTag;
```

そしてそして、`GoToBuy`の変種、`GoToBuyImpl`という`trait`を定義します。 この新しい`trait`は、型引数を取るというのがポイントです。 ここの型引数にはさっきのTag二種が入ります。 幸い`struct`の型引数と違い、`trait`の型引数は中で一切使わなくてもコンパイラに怒られたりはしませんので、型引数は一切内部で利用しません。

そして、果物屋さんかペット屋さんに行くコードを、それぞれ`impl GoToBuyImpl<FruitTag>`と`impl GoToBuyImpl<AnimalTag>`で記述します。
この型引数を与えられた`trait`ふたつは違う`trait`扱いなので、衝突エラーは発生しません：

```rust
trait GoToBuyImpl<ItemTypeTag> {
    fn go_to_buy_impl();
}

impl<T> GoToBuyImpl<FruitTag> for T {
    fn go_to_buy_impl() {
        println!("果物屋さんにGo!");
    }
}

impl<T> GoToBuyImpl<AnimalTag> for T {
    fn go_to_buy_impl() {
        println!("ペット屋さんにGo!");
    }
}
```

まだもう少しコードを書く必要があります。
次に、各種商品に自分がどのTagに対応するのかを設定します。 `trait Item`という`trait`を作り、関連型を`impl`させることで設定できます：

```rust
trait Item {
    type TypeTag;
}
impl Item for Apple {
    type TypeTag = FruitTag;
}
impl Item for Banana {
    type TypeTag = FruitTag;
}
impl Item for Cherries {
    type TypeTag = FruitTag;
}
impl Item for Cat {
    type TypeTag = AnimalTag;
}
impl Item for Dog {
    type TypeTag = AnimalTag;
}
```

そして最後に、`GoToBuy`から`GoToBuyImpl`への橋渡しをしてやります。
つまり商品ごとに、対応するTagを`Item::TypeTag`から取り出し、それを`GoToBuyImpl`に渡してやるというわけです：

```rust
impl<T> GoToBuy for T
where
    T: Item + GoToBuyImpl<T::TypeTag>,
{
    fn go_to_buy() {
        T::go_to_buy_impl()
    }
}
```

この`impl`は、`GoToBuy`を`T`に対して`impl`している怖いパターンですが、他に`GoToBuy`の`impl`は存在しないので衝突は起こりません。 セーフです。

この手法の最大のメリットは、`Apple`などの型のほうにはノータッチで済ませられることです。 たぶん実用上では`trait`よりも型の方が自分でいじれないケースが多いと思います(知らんけど)。 デメリットはコードの記述量が長くなりがちなところで、なんか新しいほにゃららimplって`trait`とそれへの橋渡しを書かなきゃいけなくなったり、`impl Item for Apple`とかを何度も書かなきゃいけないことですね。 所詮は3行/型なので許容範囲だとは思いますが。