Rust における String -> &str 操作

(自分が前書いた [Scrapbox の内容](https://scrapbox.io/kash/Rust_%E3%81%AB%E3%81%8A%E3%81%91%E3%82%8B_String_-%3E_&str_%E6%93%8D%E4%BD%9C%E3%81%AE%E9%81%95%E3%81%84) を軽くまとめたものなので中身はそこまで変わらないです)
(なんなら Scrapbox の方が詳しい可能性もあります)

# 最終的な結論
どれでも同じだが、`.as_str()` 使えば良いです。

# 前置き
Rust において `String` から `&str` に、またはその逆に変換したいことはあると思います。
が、やり方は複数個あるため違いがわかりにくいかと思います (実際、ドキュメントの記載にないものもあるので余計混乱しやすいかもしれません、自分はそうでした)。
なので、今回は `String` から `&str` に変換するやり方を 5 つ取り上げてそれぞれ Rust 本体のソースコードも踏まえて説明します。

# 環境
- Rust: 1.69.0
- [Rust Playground](https://play.rust-lang.org/) で実行
    - 実際に使ったソースコードは[こちら](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=af6d2538a50006704ba86bc41bbd1ea3)

# 紹介する変換方法
- `as_str（）`
- `Borrow` トレイトを用いた変換
- `AsRef` トレイトを用いた変換
- 参照
- 参照 + スライス

# 実験ソースコード
```rust
use std::borrow::Borrow;

fn main() {
    let s = "foo";
    let s1 = s.to_string();
    let s2 = s.to_string();
    let s3 = s.to_string();
    let s4 = s.to_string();
    let s5 = s.to_string();
    
    // as_str()
    assert_eq!(s1.as_str(), s);
    // borrow()
    let string_borrow: &str = s2.borrow();
    assert_eq!(string_borrow, s);
    //assert_eq!(s2.borrow() as &str, s);
    // as_ref()
    let string_as_ref: &str = s3.as_ref();
    assert_eq!(string_as_ref, s);
    //assert_eq!(s3.as_ref() as &str, s);
    // slice
    assert_eq!(&s4[..], s);
    // ref only
    assert_eq!(&s5, s);
}
```

# 解説
## `as_str()`
```rust
assert_eq!(s1.as_str(), s);
```
1.7.0 で追加された String 専用のメソッド。
実装は、`&self` をそのまま返している[^1]。
`&self` で `&str` を返せるのは `String` が `Deref` トレイトを実装しているため[^2][^3]。

## `Borrow` トレイトを用いた変換
```rust
let string_borrow: &str = s2.borrow();
assert_eq!(string_borrow, s);
```
`Borrow` トレイトで実装されている `borrow()` メソッドで変換。
実装は `&self[..]` を返している[^4]。
`Borrow` トレイトは prelude されていない (最初から使えるわけではない) ので、
```rust
use std::borrow::Borrow;
```
で使えるようにする必要がある。
また、後述する `AsRef` トレイトでもそうだが、`String` には複数の `Borrow` トレイト実装があるため、型を明記しないとコンパイルエラーを吐く。

## `AsRef` トレイトを用いた変換
```rust
let string_as_ref: &str = s3.as_ref();
assert_eq!(string_as_ref, s);
```
`AsRef` トレイトで実装されている `as_ref()` メソッドで変換。
実装は `as_str()` メソッドと全く同じ[^5]。
こちらは prelude されているので `use` を使わなくても使用できる。
また、`Borrow` トレイトと同様に型を明記しないとコンパイルエラーを吐く。

## 参照
```rust
// ref only
assert_eq!(&s5, s);
```
`as_str()` で説明したように、`String` が `Deref` トレイトを実装しているため参照で `&str` を返せる。
注意点として、`&String` と型推論される場合があるので、これを使用する場合は型明記した方がいいかもしれない。

## 参照 + スライス
```rust
// slice
assert_eq!(&s4[..], s);
```
参照でほぼ解決してる感じはあるけど、`&str` 自体はスライスなのでこのように参照とスライスで表記できる。

# 結果と結論
どの方法も実装は多少異なれど、同じ内容なので、`as_str()` を使うのが一番わかりやすい (実際メソッド名で一発で変換していることがわかるので)。

# 余談
`String` の実態は `Vec<u8>`[^6] なのでもしかしたら参照と参照 + スライスで実際は構造が違う可能性はあるかもしれません…。
`Vec<T>` が `cap`, `len` 等の中身を持つ構造体なので、その値がその二つで異なる可能性はあるかと思います (実際に実験はしてないので検証は必要ですが…)。 

# 参考文献
https://rs.nkmk.me/rust-str-string-conversion/

[^1]: https://doc.rust-lang.org/src/alloc/string.rs.html#884
[^2]: https://doc.rust-lang.org/src/alloc/string.rs.html#2442-2449
[^3]: トレイトおよび Deref トレイトは今回は説明を省略していただきます…一応、The Rust Programming Language に説明はあるのでそれ確認していただければ
[^4]: https://doc.rust-lang.org/src/alloc/str.rs.html#188
[^5]: https://doc.rust-lang.org/src/alloc/string.rs.html#2636
[^6]: https://doc.rust-lang.org/src/alloc/string.rs.html#365-367