type coercion(型強制)に慣れ親しむ

# type coercion(型強制)に慣れ親しむ

##  はじめに

rust使い始めて2ヶ月くらいなのですが、rust面白いです[^method_chain]。その中で、型変換の解釈が結構むずいなと思いました。 

コンパイラのいうこと聞いてそれっぽく直しておけばなんとかなることが大半なのですが、たまに理解できないエラーが出る&納得してコード書きたいので、rustのtype coercion(型強制)についてまとめました。公式ドキュメントにも散らばって記載されている情報なので、間違った所あるかもしれないのですが、指摘してくださればありがたいです！

[^method_chain]: というより、メソッドチェーンが爽快な言語だと思う。

## トピック

rustのtype coercion(型強制)のルールと例をいくつか。

## 想定する対象者

rustの基本的な文法がだいたいわかるくらいのレベルの人。具体的には、https://rustbyexample.com 内のコードがだいたいわかればオッケーだと思います。


## coercionを理解することによって生じる効用

+ 型に関するコンパイルエラーに振り回されずにすむ => めっちゃ快適にコードが書けて、コード書くのが気持ちよくなる:yum:

+ 実行速度的な意味で効率的なコードを書きやすくなる(無駄なコピーとかする場所を減らせたり)

# 準備

本編に入るための準備事項を記載します。

## self

+ syntax sugar

```rust
struct T;

impl T {
    fn method1(self) {}
    fn method2(&self) {}
    fn method3(&mut self) {}
} 
```

の`fn method2(&self)`は実は`fn method2(self: &T)`のsyntax sugarです[^self_desugar]
同様に、`fn method1(self: T)`, `fn method3(self: &mut T)`となります。

[^self_desugar]: https://github.com/rust-lang/rfcs/blob/73ee34aada32725bda1401dbd1f251e72f5d00d6/text/0401-coercions.md#coercions-of-receiver-expressions を見れば良さげ。後は、 https://rustbyexample.com/fn/methods.html にもcommentに説明が書いてある。

+ Universal Function Call Syntax(UFCS)

`receiver: Type`(paramter type)として、`receiver.method(args)`の場合、`Type::method(receiver, args)`という風にも書き換えられます。特に、`Type`が`Trait`であることを強調したい場合は、`<Type as Trait>::method(receiver, args)`とすれば良いです。この記法をUniversal Function Call Syntax(UFCS)または、Fully Qualified Syntax(FQS)といいます[^fqs_ufcs]。

[^fqs_ufcs]: FQSの説明は、https://doc.rust-lang.org/stable/book/second-edition/ch19-03-advanced-traits.html#fully-qualified-syntax-for-disambiguation にある。UFCS自体は、https://doc.rust-lang.org/book/first-edition/ufcs.html#universal-function-call-syntax にある。多分両者は同じ。

## deref

derefの基本的な説明については、https://rust-lang-ja.github.io/the-rust-programming-language-ja/1.6/book/deref-coercions.html をみればいいかなと思います。(雰囲気的には`&String`を`&str`に自動的に変換してくれたりできるのはderefトレイトのおかげですよ、みたいなことを言っている)

---

さて、上のリンクの中でちょっと気になる点があり、

> このルール(著者注: derefによる型強制(deref coercion)) はRustが自動的に変換を行う唯一の箇所の一つです。

ということが書いてありますが、実はちょっと正確じゃないです。[^deref_coercion] 例えば、


```rust
let arr: [i32;5] = [1,2,3,4,5];

let n = arr.first().unwrap(); // 1
// または、
let arr2: Vec<i32> = arr.iter().map(|s| s*2).collect();
```

みたいなコードを考えます。`arr`はprimitiveのarray型ですが、[arrayのドキュメント](https://doc.rust-lang.org/std/primitive.array.html)を見ても、`iter`メソッドも`first`メソッドも存在しません(`into_iter`はありますけど)。
また、このarrayのドキュメントの冒頭に`Arrays coerce to slices ([T])`と書いてありますが、これはどういうことでしょうか？[deref](https://doc.rust-lang.org/std/ops/trait.Deref.html)を見ても、arrayとDerefトレイトが関係する部分は一つもないですよね。

というわけで、最初は調べれば調べるほど謎だらけでした。こういった、「謎の部分」を解き明かそうというのが本記事の目的です。(ちなみに後半の例にこの例の解釈を書きました)

[^deref_coercion]: そもそも`唯一の箇所の一つ`って、唯一なのかそうでないのかどっちなんだよって感じがする。ちなみに原文は`This rule is one of the only places`でした。


# 概要

とりあえず、coercionの概要からまとめたいと思っています。ちょっと形式的なので、退屈に感じる方がいらっしゃるかもです。
なので、実践的な内容から触れたい人は、本記事の「例」から見ていただければ。[RFC0401](https://github.com/rust-lang/rfcs/blob/73ee34aada32725bda1401dbd1f251e72f5d00d6/text/0401-coercions.md) を中心としたお話です。以降、断りなく`T`や`U`はparameter typeとします。

そもそも型変換の大きな枠組みとしては、`subtyping`, `coercion`, `casting`があります。今回詳細にお話するのが`coercion`ですが、他の２つについて軽く触れておきます：

+ `subtyping` .. lifetimeに関する型チェックと暗黙的な型変換。lifetime `'a`が`'b`よりも長いlifetimeを持つとき、`'a`  は `'b` のsubtypeという。subtypingのモチベーションも含めた話だと、https://doc.rust-lang.org/book/second-edition/ch19-02-advanced-lifetimes.html#lifetime-subtyping がわかりやすい。referenceとしては、 https://doc.rust-lang.org/reference/subtyping.html とか https://doc.rust-lang.org/beta/nomicon/subtyping.html を参照。

+ `casting` .. `as`を用いた明示的な型強制。詳しくは、https://rust-lang-ja.github.io/the-rust-programming-language-ja/1.6/book/casting-between-types.html#as を参照。

---

それでは、`coercion`について詳しく触れたいと思います。上記のリンクの他に、https://doc.rust-lang.org/beta/nomicon/coercions.html にも簡潔な説明があります。

## coercionの種類

coercionにはいくつか種類があります。

1. [Deref coercion] Derefトレイトによるcoercion. `T` が `Deref<Target = U>`を実装していれば、`&T`から`&U`に型変換される。

2. [Pointer weakening] 
  1. mutabilityが除去されて変換される: `&mut T → &T`とか`*mut T → *const T`
  2. raw pointerに変換される：`&mut T → *mut T` とか `&T → *const T`

3. [Unsizing] `&[T; N]`から`&[T]`への変換とか[^unsizing]


[^unsizing]: もうちょっとしっかりいうと、`T`が`Unsize<U>`を実装していて、かつ、`Ptr<T>`が`CoerceUnsized<Ptr<U>>`を実装しているならば、`Ptr<T>`が`Ptr<U>`に型変換される。ここで、`Ptr`とは、例えば、`&T, *mut T, Box, Rc`などのPointer typeを表す。`[T; N]`は`Unsize<[T]>`を実装しているので( https://doc.rust-lang.org/std/marker/trait.Unsize.html を参照) `&[T; N]`は`&[T]`に変換できるというわけです。

また、[RFC0401](https://github.com/rust-lang/rfcs/blob/73ee34aada32725bda1401dbd1f251e72f5d00d6/text/0401-coercions.md)内では、`coercion`は推移的(transitive)に作用します。つまり、`T1`から`T2`へcoerceでき、かつ、`T2`から`T3`にcoerceできる状況ならば、`T1`から`T3`へのcoercionが可能です。[transitivity case]

注) しかしながら、現時点ではtransitivityは完全に実装されていないそうです。(2017/11/17現在で[issue #18602](https://github.com/rust-lang/rust/issues/18602)がopenのまま) ここの部分に関して、私自身、最初、例えば、`&&&[i32; 5]`から`&[i32]`へなぜ型変換できないのかちょっとわかりませんでした。
(`&[i32; 5]`から、`&[i32]`へは`unsized coercion`の効果で変換できることに注意。また、derefのみに限って言えば、推移的に作用できる。つまり、`&&&[i32; 5]`から`&[i32; 5]`へも、二回のdereferenceで型変換に成功する[^deref])。
結果的に[stackoverflow](https://stackoverflow.com/questions/47237733/why-doesnt-a-nested-reference-to-an-array-coerce-to-a-slice)で質問してみて、coercionのtransitivity caseに実装が未だ対応していないことが分かったので、よかったら見てください:ok_hand_tone1:

[^deref]: たとえば、https://rust-lang-ja.github.io/the-rust-programming-language-ja/1.6/book/deref-coercions.html に`型がマッチするまで必要なだけ繰り返します。`と書いてある

## receiver coercion

methodのreceiverの型変換については、特別なcoercion rule(receiver coercion)が適用されます。(`receiver.method(args) ↔ Type::method(receiver, args)`を思い出しましょう) つまり、receiverからmethodの第一引数(`self`とか`&self`とかだったり)の型変換には以下の特別ルール[^receiver_coercion_name]が適用されます：

[^receiver_coercion_name]: 各名称に関しては、https://doc.rust-lang.org/nomicon/dot-operator.html および、このドキュメントの参照リンクの https://stackoverflow.com/questions/28519997/what-are-rusts-exact-auto-dereferencing-rules/28552082#28552082 を参考にしました。

1. [by-value-method] methodの第一引数が`T`だった場合、つまり、`method(self: T)`だった場合は、このメソッドが使われる(要するに、完全一致の場合はそれ使うよ！ってだけの話です)

2. [autorefd method] 1で一致しなかった場合は、receiverに`&`か`&mut`をつけた結果、methodの第一引数の型と一致した場合、つまり`method(self: &T)` or `method(self: &mut T)`だった場合は当てはまった方のmethodが使われる。

3. [auto-dereferencing rule] 1,2でもマッチしなかった場合は、前節の[Deref coercion]か[Unsizing coercion]が適用される。

4. 3を複数回適用した後に、1,2で条件がマッチするならば、1か2に戻って、型が一致する。(ここで、transitive(推移的)との兼ね合いについて気になった方は、脚注の[^receiver_coercion]を読んで下さい)

5. 1~4によって型の一致がおこらなかった場合は、コンパイルエラーになる。

[^receiver_coercion]: で、この先めちゃややこしいんですが、このcoercionはマッチするまでのcoercionの回数を**1度だけ**とみなします。例えば、receiverの型が`&&[i32; 3]`で、methodの第一引数の要求されている型が`&[i32]`としましょう。この時、`&&[i32; 3]`=(3)=>`&[i32; 3]`=(3)=>`&[i32]`=(1)=>`&[i32]`のように推移していき型一致を確認しますが、この過程のcoercionを一度きりであるとみなします。つまり、、何が言いたいかというと、普通のcoercionの場合、該当部分に関して`transitive rule`は未実装なので[^attention]、`&&[i32; 3]`=(3)=>`&[i32; 3]`までで型変換が終わり(次の`&[i32; 3]`から`&[i32]`への変換は2回目に行われるcoercionなので)、型不一致でコンパイルエラーとなってしまいます。しかしながら、このreceiver coercionは、`transitive rule`が適用されない状況下にあるので、適切に型一致されます。そこの挙動がよくわからなかったのでこの両者の違いを[stackoverflow](https://stackoverflow.com/questions/47237733/why-doesnt-a-nested-reference-to-an-array-coerce-to-a-slice)にて質問してみたのでした。特殊ケースなので通常は意識する必要はないですが、RangeFullの例に登場したりするので、頭の片隅にでも入れておくといつか役立つはずです。

はい。以上がcoercionのルールとなります。これでわかった方は天才なので:sunglasses:、お待ちかねの例で確認していきます。

# 例

以下では、なるべく簡単な例から徐々に解釈の難しい例題にステップアップして、coercionのルールの様相をつかみたいなと思います。coercionの働く例と、coercionと関係しそうだがそうでない例 の構成です。なるべく実践に出てきそうなコードで確認していきたい。

## autorefd method

```rust
fn main() {
    let s = "abc".to_string(); // let s: String;
    let _n = s.len(); //let n: usize = 3;
}
```

何の疑問も無さそうなコードですが、敢えて深掘りしましょう。`len`メソッドの第一引数は`&self`なので、`s: String`と型が合わないです。(selfの節のsyntax sugarの部分から`self: &String`と`&self`は同値なのでした)
前章のルールと照らし合わせれば、`receiver coercion`の[autorefd-method]が適用されることで、https://doc.rust-lang.org/std/string/struct.String.html#method.len が実行されます。
ここで大事なポイントとしては、わざわざ、`let _n = (&s).len();`のようにする必要はない、ということです(もちろん`&`つけても、`receiver coercion`の[by-value-method]が適用され、うまくいく)。

## auto-dereferencing rule

```rust
fn main() {
    let s = "abc\nあああ\nbcd\n".to_string(); // String
    let buf = s.lines().collect::<Vec<_>>(); // let buf: Vec<&str>
}
```

これも似たような感じですが、まず`receiver coercion`の[auto-dereferencing rule]が適用されるところが違います。(linesメソッドはhttps://doc.rust-lang.org/std/string/struct.String.html#method.lines の通り、`str`でしか定義されていないメソッドです) つまり、

```
         3        2
`String`===>`str`===>`&str`
```

のようにcoerceされます[^arrow_2](番号は`receiver coercion`のルールの番号に対応しています)

[^arrow_2]: 矢印が複数ありますが、`receiver coercion`なので、coercionは一回のみなされたとみなします

## Deref coercion

```rust
fn len_str(s: &str)-> usize {
    s.len()
}

fn main() {
    let s = "abc".to_string(); // String
    let _n = len_str(&s); // 3
    //let _n = s.len(); //let n: usize = 3;
}
```

selfが関係しないただの関数の場合。
sはString型ですが、通常のcoercionの中の1の[Deref coercion]が作用されて、`&String`が`&str`となり、`len_str`が実行されます。


## array coerced to slice

一番はじめに問題提起した例を見てみます：

```rust
fn main() {
    let arr = [1,2,3,4,5]; // [i32;5]
    
    let n = arr.first().unwrap(); // 1
    // あるいは以下の例：
    // https://doc.rust-lang.org/std/primitive.i32.html#impl-Mul<i32>-1 があるので、s: &i32と2: i32の掛け算ができる
    let arr2: Vec<i32> = arr.iter().map(|s| s*2).collect();
}
```

`[i32;5]`にfirstやiterメソッドは存在しないので、`receiver coercion`の[auto-dereferencing rule]が適用されます。
つまり、

```
          3          2
`[i32;5]`===>`[i32]`===>`&[i32](slice)`
```

の変換が行われ、slice型には,[first](https://doc.rust-lang.org/std/primitive.slice.html#method.first)や[iter](https://doc.rust-lang.org/std/primitive.slice.html#method.iter)があり、これらのメソッドの第一引数は`&self`なので、型一致を確認します。


## `& mut`


```rust
use std::io::{self, BufReader, BufRead};
fn main() {

    let data = "city\tcountry\tpopulation";
    let mut reader = BufReader::new(data.as_bytes());
    
    let mut line = String::new();
    // fn read_line(&mut self, buf: &mut String) -> Result<usize>
    let len = reader.read_line(&mut line).unwrap();
}
```

これまたよくある例。receiverである`reader`変数は`BufReader<io::Stdin>`型ですが、`receiver coercion`の[autorefd method]により、`&mut`が付加され、read_lineメソッドの第一引数である`self: &mut BufReader<io::Stdin>`と一致します。(なので、`let len = (&mut reader).read_line(&mut line).unwrap();`とかしなくていいです。)
一方、read_lineの第2引数も`&mut`ですが、こちらは`&mut line`のように、`&mut`を明示的に付ける必要があります。(`&`だけつけるのはだめ) なぜなら、`receiver`の型変換ではないため、[autorefd method]のルールが適用されず、かといって、derefでサポートされる範囲では`&String`から`&mut String`への変換もできないからです。

ちなみに、`reader`変数には`mut`が必要です。[autorefd method]が働くと言っても、immutableなものをmutableに変更することはできません：

```rust
fn main() {
    let x: i32 = 4;
    // let y: &mut i32 = &mut x; // cannot borrow immutable local variable `x` as mutable

    let mut x: i32 = 4;
    // expected type `&mut i32`, found type `&i32`
    // let y: &mut i32 = &x; // Error: types differ in mutability: 
    let y: &mut i32 = &mut x; // mutable borrow occurs here
}
```

## IndexとRangeFull

お次は、たまによく見る`&v[..]`と`&v`の違いについてです。正直初見では、読まなくて良い小節ですが(`Deref coercionが作用しない例`の節まで飛んでください)、フルに上記のcoercionのルールを使うため、敢えて触れておきます。

ちなみに、`RangeFull`とは、`..`(double ellipsis)のことです[^rangefull_doc]。よく文字列で`&v[..]`のような書き方をしますが、簡単のため、整数のスライスで違いを確認していきます。(文字列の場合でも、同じように定義を辿っていけば、考え方は同じです[^stack])

[^stack]: https://stackoverflow.com/questions/31797599/what-does-the-double-ellipsis-operator-mean-in-the-context-of-a-str-subscript とかも参考にしてください。

[^rangefull_doc]: https://doc.rust-lang.org/std/ops/struct.RangeFull.html を見たほうが早いかも。

```rust
fn func(slice: &[i32])->i32 {
    slice.iter().sum()
}

fn main() {    
    let buffer: &&[i32; 4] = &&[0,1,2,3];
    
    let m: i32 = buffer.iter().sum(); // 6
    //let m: i32 = func(buffer); // Error: expected slice, found &&[i32; 4]
    let m: i32 = func(&buffer[..]); // 6
}
```

ちょっと意地悪な例を作ってみました。実は、真ん中の例がエラーになり、後の２つはOKとなります。coercionの知識がないと、この挙動を真に理解するのはむずい:sweat: 
なんでこういうことが起こるのかを今から説明したいです。

----

まず一番上の例(`let m: i32 = buffer.iter().sum();`)から。これは、`array coerced to slice`の例とほぼほぼ同じで、以下のようにcoerceされるからです：

```
[receiver coercionの起こる手順(番号はreceiver coercionの節のルールに対応)]

            3             3          1
`&&[i32;4]`===>`&[i32;4]`===>&[i32]`===>`&[i32]`
```

`iter`は`self: &[i32]`なので、これで型一致がなされて、正常に処理されます。


----

2番目の例(`let m: i32 = func(buffer)`)に行きましょう。これは、selfが絡んでこないので、通常のcoercionのルールが適用されます。。なぜ、型変換できないのか？それは、[transitivity case]の注)に書いた未実装のお話と絡みます。

```
[coercionの起こる手順]

          Deref         UnSizing    
`&&[i32;4]`===>`&[i32;4]`- - -?>&[i32]
```


これらは、２つの異なるcoercionが絡むので、transitivity case(推移的にcoercionが行われるケース)に相当しますが、注)により、これらの変換は未実装のため、`- - -?>`のとおり、移動できず、コンパイルエラーになります。
もちろん、```let m: i32 = func(&[0,1,2,3])```とだったら、問題ないですよね。

----

さて、最後の例(`let m: i32 = func(&buffer[..])`)を見ていきます。こちらはうまくいきますが、一体何が起こっているのでしょうか？

実は、[Indexのドキュメント](https://doc.rust-lang.org/core/ops/trait.Index.html)を見ると、`container[idx]`は、 `*container.index(idx) ↔ *std::ops::Index::index(&container, idx)`であることが書いてあります。
indexメソッドは(arrayではなく、)sliceモジュールの中にあり、そのシグネチャは`index(self: &[T], index: RangeFull) -> &[T]`です。(なので、`&buffer[..]`のように`&`が必要[^dot_op]。)

[^dot_op]: https://doc.rust-lang.org/reference/expressions.html#index-expressions も。詳しく言うと、`&container[..]`は明示的にカッコを付けると、`(&(*(container.index(..)))`の順で計算されます。

さて、`func(&buffer[..]);`の引数`&buffer[..]`について、bufferは`&&[i32; 4]`です。ここで、bufferはreceiverなので、`receiver coercion`が働くことに注意すると、`&buffer[..]`は、以下のようにcoerceされ、indexの第一引数である`&[i32]`に以下のように型一致します。：

```
            3             3           1
`&&[i32;4]`===>`&[i32;4]`===>`&[i32]`===>`&[i32]`
```

ようやく、`&buffer[..]`の型が`&[i32]`となることがわかりました。此処から先は自明です。なぜなら、`func`関数が`&[i32]`自体を引数に取るので、最後の例が正常に動作するからです。

----

[^precedence]: https://doc.rust-lang.org/reference/expressions.html#operator-precedence を参考

長くなってしまったので、`v: &[T; N]`として、`&v[..]`と`&v`の違いについてまとめておきます。両者は関数の引数が要求する型が`&[T]`であったときに動作が異なります。

+ `&v[..]`の方は、引数として与えられる前に(`receiver coercion`のおかげで)すでに型変換されて`&[T]`になるので、funcの引数(`&[T]`)と完全一致して問題ない。

+ `&v`の方は`&&[T; N]`から`&[T]`にcoerceしようとしてうまくいかないので、コンパイルエラーになる。


----


## coercionが作用しない例

coercionが発生する場所については、https://doc.rust-lang.org/beta/nomicon/coercions.html の`Coercions occur at a coercion site.`の段落で述べられているのですが、ちょっとこれだけではわかりづらいと思います。

そこで逆に考えて、一見coercionが適用されそうだけど、実はそうでない例をあげていきたいと思います。

### クロージャー

```rust
fn main() {    
    let v: Vec<String> = vec!["abc".to_string(), "cde".to_string()];
    let w: Vec<&String> = v.iter().map(|s| s).collect(); // Vec<&str>とするとエラー
}
```

ちなみに、`w`の型を`Vec<&str>`とすると、

```txt:error
error[E0277]: the trait bound `std::vec::Vec<&str>: std::iter::FromIterator<&std::string::String>` is not satisfied
 --> src/main.rs:5:47
  |
5 |     let sv2: Vec<&str> = sv.iter().map(|s| s).collect();
  |                                               ^^^^^^^ a collection of type `std::vec::Vec<&str>` cannot be built from an iterator over elements of type `&std::string::String`
  |
  = help: the trait `std::iter::FromIterator<&std::string::String>` is not implemented for `std::vec::Vec<&str>`
```

となり、コンパイルエラーとなります。
何故かと言うと、mapメソッドの引数の型は`FnMut(&String)->&String`となっていて、output typeの`&String`が`&str`にcoercionしないからです。つまり、クロージャーの型推論はcoercionの範疇外であることを示しています。

なので、高階関数を使う際はしっかりクロージャーの型を把握している必要があります。実践でも高階関数内のクロージャーの型不一致でよくコンパイルに注意されますよね:frowning2: 逆に言うと、実践的にはここさえ抑えれば70~80%くらいのコンパイルエラーは回避できるのではないかな、と。

代替案としては、例えば

```rust
let w: Vec<&str> = v.iter().map(|s| s.as_str()).collect();
let w: Vec<String> = v.clone().into_iter().map(|s| s).collect(); // もしこの先、vを使わないなら、cloneつけなくて良い
let w: Vec<String> = v.iter().map(|s| s.to_string()).collect();
// let w: Vec<String> = v.iter().map(|s| s.into()).collect(); //Error: &StringはStringに変換できない
```

とすれば良いですね:v_tone1:


### generic type parameter

トレイト内でtype parameterが絡んでいるときも同様にcoercionは働きません：

```rust
use std::borrow::Borrow;
// use Borrow trait instead of AsRef because of join method, 
// see also, https://doc.rust-lang.org/std/primitive.slice.html#method.join
pub fn write_lines<S: Borrow<str>>(lines: &[S])->String {
    lines.join("\n")
}

fn main() {
    let s = vec!["aaa", "bbb"]; // vec<&str>
    let res = write_lines(&s); // &strはBorrow<str>トレイトを実装しているので、OK

    let s = vec!["aaa".to_string(), "bbb".to_string()]; // Vec<String>
    let res = write_lines(&s); // StringはBorrow<str>トレイトを実装しているので、"aaa\nbbb"となりOK!

    let (s1, s2) = ("aaa".to_string(), "bbb".to_string());
    let t = vec![&s1, &s2]; // Vec<&String>
    // let res = write_lines(&t); // &StringはBorrow<str>トレイトを実装していないので、Error
}
```

最後の`let t = vec![&s1, &s2]; // Vec<&String>`の例を御覧ください。`&String`は`&str`にderefしてくれそうですが、以下のエラーが出ます：

```error
error[E0277]: the trait bound `&std::string::String: std::borrow::Borrow<str>` is not satisfied
  --> src/main.rs:14:15
   |
14 |     let res = write_lines(&t);
   |               ^^^^^^^^^^^ the trait `std::borrow::Borrow<str>` is not implemented for `&std::string::String`
```

これは、traitのtype parameterのマッチのほうが優先され、`&String`が`std::borrow::Borrow<str>`トレイトを実装していないためです！
解決策として、`let t: Vec<&str> = vec![&s1, &s2];`と明示的に型を表記してあげれば、先に`&s1`, `&s2`変数の型が`&String`=> `&str`にderefしてくれるので、大丈夫になります。(根拠としては、https://doc.rust-lang.org/beta/nomicon/coercions.html に`let statements, statics, and consts: let x: U = e`と書いてある)

----

追記) `tokio`とかのネットワーク関連でよく使われる`Bytes` crateの`BytesMut`に関して、同類の例を追記。

```rust
extern crate bytes;

use bytes::BytesMut;


fn main() {
    let bytes = b"hello world"; // &[u8; 11]
    // Error: the trait `std::convert::From<&[u8; 11]>` is not implemented for `bytes::BytesMut`
    // Fromトレイトが関係しているので、`&[u8; 11]`から`&[u8]`のcoercionは働かない
    //let mut a = BytesMut::from(bytes);

    // &[u8]
    let mut a = BytesMut::from(&bytes[..]);
}
```

```rust
extern crate bytes;

use bytes::{BytesMut, BufMut};


fn main() {
    let mut a = BytesMut::with_capacity(64);
    // Error: the trait `bytes::Buf` is not implemented for `&[u8; 11]`
    // put<T: IntoBuf>(&mut self, src: T)
    // putは引数にIntoBufトレイトの型を要求しているので、`&[u8; 11]>`から`&[u8]`のcoercionは働かない
    // a.put(b"hello world");

    // &[u8]はIntoBufを実装しているので、OK
    a.put(&b"hello world"[..]);
}
```

一つ目の例は、`From`トレイトが、２つめは`InfoBuf`トレイトが関係しているので、type coercionは起こりません。`&b"hello world"[..]`に関しては、`RangeFull`の節でも紹介しましたが、`&b"hello world"[..]`がまず評価され、`&[u8]`となります。ここで、`&[u8]`はInfoBufトレイトを実装している型のため、型一致します。

---

もう一つ例を。比較演算子の場合です。難易度高めなので、すでにこの時点でキツければ飛ばしてください。

```rust
fn main() {
    let s0: &String = &("abc".to_string());
    let flag0 = (s0 == "abc");
    let s1: &&String = &&("abc".to_string());

    let flag1 = (s1 == "abc"); 
}
```

この時、`flag0`は評価に成功しますが、`flag1`の箇所のみコンパイルエラーとなります：

```log:error.log
error[E0277]: the trait bound `&std::string::String: std::cmp::PartialEq<str>` is not satisfied
 --> src/main.rs:6:21
  |
6 |     let flag1 = (s1 == "abc"); 
  |                     ^^ can't compare `&std::string::String` with `str`
  |
  = help: the trait `std::cmp::PartialEq<str>` is not implemented for `&std::string::String`
  = note: required because of the requirements on the impl of `std::cmp::PartialEq<&str>` for `&&std::string::String`
```

一番下の`note: ..`に記載されているとおりなのですが、噛み砕いて説明していきます。

注) ちなみに、`&&String`->`&str`へは、coercionが上手くいかないが、`&String`=>`&str`へはderef coercionが効くから、**ではないです。**(つまり、この問題では、`transitivity case`が未実装ということと何の関係もないです。)

まずは、前者の`let flag0 = (s0 == "abc")`から。

いつもの通り、[PartialEqのドキュメント](https://doc.rust-lang.org/std/cmp/trait.PartialEq.html) をまず見ましょう[^partial_eq]。

[^partial_eq]: そもそも、なぜ、Eqトレイトではなく、PartialEqなのかは、例えば、https://qiita.com/lo48576/items/343ca40a03c3b86b67cb とかがわかりやすいと思う。

```a == b ↔ a.eq(&b) ↔ <T as PartialEq<Rhs>>::eq(self: &T, other: &Rhs)```

であることに注意すると、


```rust
// https://doc.rust-lang.org/std/primitive.reference.html#impl-PartialEq<&'b%20B>-1
impl<'a, 'b, A, B> PartialEq<&'b B> for &'a A 
where
    A: PartialEq<B> + ?Sized, // 例の場合、B=strです。
    B: ?Sized, 
```

および、

```rust
// https://doc.rust-lang.org/std/string/struct.String.html#impl-PartialEq<&'a%20str>
impl<'a, 'b> PartialEq<&'a str> for String
```

なので、`impl<'a, 'b> PartialEq<Rhs=&'a str> for &'b String`が言えます。ということで、`s0 == "abc"`が評価できる。

一方、後者の方はどう頑張っても、`std::cmp::PartialEq<&str> for &&std::string::String`とはできません。なので、コンパイルエラーになってしまいます。

ということで、coercionとは何の関係もありませんでした。ちなみに、`==`をスワップして

```rust
fn main() {
    let s0: &String = &("abc".to_string());
    let flag0 = ("abc" == s0);
    let s1: &&String = &&("abc".to_string());

    let flag1 = ("abc" == s1); 
}
```

としても、`flag0`は評価される一方、`flag1`の部分で以下のコンパイルエラーが出ます。~~暇な~~自由になりたい人は上記と同様の考察をして試してみてください:innocent:

```log:error.log
error[E0277]: the trait bound `str: std::cmp::PartialEq<&std::string::String>` is not satisfied
 --> src/main.rs:6:24
  |
6 |     let flag1 = ("abc" == s1); 
  |                        ^^ can't compare `str` with `&std::string::String`
  |
  = help: the trait `std::cmp::PartialEq<&std::string::String>` is not implemented for `str`
  = note: required because of the requirements on the impl of `std::cmp::PartialEq<&&std::string::String>` for `&'static str`
```


---
Note) そうやけど、前提として上みたいな糞コードなんて普通書かんやろって思いませんでしたか？ では、以下のコードはどうでしょうか？：

```rust
let s0: &String = &("abc".to_string());
assert_eq!(s0, "abc"); // OK

let s1: &&String = &&("abc".to_string());
assert_eq!(s1, "abc"); // Error
```

`assert_eq!`は、以下のように定義されています[^assert_eq_github]：

[^assert_eq_github]: https://github.com/rust-lang/rust/blob/6a92c0fdbddbda6fcb0c6215f64240d228e4b2f5/src/libcore/macros.rs#L111-L138 参照。後半の`($left:expr, $right:expr, $($arg:tt)+)`から先の部分は本文で解説していることと同じなので省略。

```rust
macro_rules! assert_eq {
    ($left:expr, $right:expr) => ({
        match (&$left, &$right) {
            (left_val, right_val) => {
                if !(*left_val == *right_val) {
                    panic!(r#"assertion failed: `(left == right)`
  left: `{:?}`,
 right: `{:?}`"#, left_val, right_val)
                }
            }
        }
    });
```

一度3行目でrefとってから、5行目でdereferenceしているところが違いますが、いずれにしろ比較演算子`==`を用いているので、実質、上の「糞コード」と同じです。(ちなみに、match文はcoercion site[^coercion_site]ではありません。)

[^coercion_site]: https://doc.rust-lang.org/beta/nomicon/coercions.html を参照。


```log:error.log
error[E0277]: the trait bound `&std::string::String: std::cmp::PartialEq<str>` is not satisfied
 --> src/main.rs:6:1
  |
6 | assert_eq!(s1, "abc"); // Error
  | ^^^^^^^^^^^^^^^^^^^^^^ can't compare `&std::string::String` with `str`
  |
  = help: the trait `std::cmp::PartialEq<str>` is not implemented for `&std::string::String`
  = note: required because of the requirements on the impl of `std::cmp::PartialEq<&str>` for `&&std::string::String`
```

同じコンパイルエラーですね:raised_hands_tone1:

----

追記) また、 `BytesMut`の例。(こちらのほうがわかり易い例かも..)

```rust
extern crate bytes;

use bytes::{BytesMut, BufMut};


fn main() {
    let mut a = BytesMut::with_capacity(64);
    a.put(&b"hello world"[..]);

    // can't compare `bytes::BytesMut` with `[u8; 11]`
    assert_eq!(a, b"hello world");
}
```

とすると、以下のようなエラーとなります：

```error.log
error[E0277]: the trait bound `bytes::BytesMut: std::cmp::PartialEq<[u8; 11]>` is not satisfied
  --> src/main.rs:16:5
   |
16 |     assert_eq!(a, b"hello world");
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't compare `bytes::BytesMut` with `[u8; 11]`
   |
   = help: the trait `std::cmp::PartialEq<[u8; 11]>` is not implemented for `bytes::BytesMut`
   = note: required because of the requirements on the impl of `std::cmp::PartialEq<&[u8; 11]>` for `bytes::BytesMut`
```

これは、PartialEqトレイトが関係するので、変数`a`は`&[u8; 11]`から`&[u8]`にcoercionせずに、型不一致を起こすからです。

一方、`assert_eq!(a, &b"hello world"[..]);`とすると、第二項の`&b"hello world"[..]`は`&[u8]`型であり、`bytes::BytesMut`は`std::cmp::PartialEq<&[u8]>`を実装しているので、評価に成功します。



# まとめ

type coercionを[RFC0401](https://github.com/rust-lang/rfcs/blob/73ee34aada32725bda1401dbd1f251e72f5d00d6/text/0401-coercions.md)に従って説明し、後半は例をあげました。
rustの型変換は思ったより難しいですが、それでもルールをおぼろげにでも把握していれば、rustを書くのがかなり快適になるはずです。後は、わからないエラーが出たときは公式ドキュメントの定義をしっかり確認すれば、本記事の例以外のエラーも自力で解決できることでしょう。