[Rust] 文字列スライス str から文字列 String への変換とその仕組み

本記事では文字列スライス `str` から文字列 `String` に変換する方法とその仕組みについてまとめます。

文字列 `String` から文字列スライス `str` への変換については別記事にしました。

参考「[[Rust] 文字列 String から文字列スライス str へ変換される仕組み - Qiita](https://qiita.com/kerupani129/items/1d170d59720328d7a7c1)」

# 0. まとめ

```rust:基本的な型変換
let ss: &str = "str";

let s = ss.to_string();
// or
let s = String::from(ss);
// or
let s: String = ss.into();
// or
let s = ss.to_owned();
```

- `String::from` は `str::to_owned` を呼ぶ
- `str::into` は `String::from` を呼ぶ
- `str::to_string` は `String::from` を呼ぶ

```rust:文字列操作が目的の変換
let ss: &str = "str";

// 文字列置換を伴う型変換
let s_replaced = ss.replace("str", "String");
// or
let s_replaced = ss.replacen("str", "String", 1);

// 繰り返しを伴う型変換
let s_repeated = ss.repeat(3);

// 大文字・小文字変換を伴う型変換
let s_ascii_lowercase = ss.to_ascii_lowercase();
// or
let s_ascii_uppercase = ss.to_ascii_uppercase();
// or
let s_uppercase = ss.to_uppercase();
// or
let s_lowercase = ss.to_lowercase();
```

# 1. 文字列スライス `str` を文字列 `String` に変換する 16 つの方法

```rust
let ss: &str = "str";

let s: String = ss.to_string();
// or
let s: String = String::from(ss);
// or
let s: String = ss.into();
// or
let s: String = ss.to_owned();
// or
use std::convert::TryFrom;
let s: String = String::try_from(ss).unwrap();
// or
use std::convert::TryInto;
let s: String = ss.try_into().unwrap();
// or
use std::str::FromStr;
let s: String = String::from_str(ss).unwrap();
// or
let s: String = ss.parse().unwrap();
// or
let s: String = String::from_utf8(ss.as_bytes().to_owned()).unwrap();

// 文字列置換を伴う型変換
let s_replaced: String = ss.replace("str", "String");
// or
let s_replaced: String = ss.replacen("str", "String", 1);

// 繰り返しを伴う型変換
let s_repeated: String = ss.repeat(3);

// 大文字・小文字変換を伴う型変換
let s_ascii_lowercase: String = ss.to_ascii_lowercase();
// or
let s_ascii_uppercase: String = ss.to_ascii_uppercase();
// or
let s_uppercase: String = ss.to_uppercase();
// or
let s_lowercase: String = ss.to_lowercase();
```

※説明のために変数全てで型指定をしていますが、型指定を省略できるものもあります。

## 1.1. UTF-8 バイト列から文字列 `String` に変換

`str` 型から変換する前に、まずは UTF-8 バイト列からの変換を確認します。

※ `to_owned` メソッドについては後述。

```rust
let ss: &str = "str";

let bytes: &[u8] = ss.as_bytes();

let bytes_owned: Vec<u8> = bytes.to_owned(); // &[u8] -> Vec<u8>

let s: String = String::from_utf8(bytes_owned).unwrap(); // Vec<u8> -> String
```

参考「[from_utf8 - String in std::string - Rust](https://doc.rust-lang.org/std/string/struct.String.html#method.from_utf8)」

## 1.2. `to_owned` メソッドで借用データを異なる型で複製し所有する

Rust における `to_owned` は `clone` (クローン、複製する) を一般化した概念で、`clone` では `&Self` 型から `Self` 型の複製を生成するのに対し、`to_owned` は `&Self` 型から `Self::Owned` 型の複製を生成します。

借用したデータをそのまま所有することはできないので、複製して所有します。

参考「[ToOwned in std::borrow - Rust](https://doc.rust-lang.org/std/borrow/trait.ToOwned.html)」

```rust
let ss: &str = "str";

let s: String = ss.to_owned();
```

`str` 型における `ToOwned` トレイトの実装は以下のようになっています。

```rust:to_owned&nbsp;メソッドの定義
impl ToOwned for str {
    type Owned = String;
    #[inline]
    fn to_owned(&self) -> String {
        unsafe { String::from_utf8_unchecked(self.as_bytes().to_owned()) }
    }
    // ...
}
```

参考「[ToOwned - str - Rust](https://doc.rust-lang.org/std/primitive.str.html#impl-ToOwned)」

`from_utf8_unchecked` 関数は `from_utf8` 関数の安全でない版で、正しい UTF-8 バイト列かどうかを確認せずに文字列 `String` に変換します。

参考「[from_utf8_unchecked - String in std::string - Rust](https://doc.rust-lang.org/std/string/struct.String.html#method.from_utf8_unchecked)」

`&[u8]` から `Vec<u8>` に型変換し所有するところでも `to_owned` メソッドを使用します。

## 1.3. `String::from` メソッドは `str::to_owned` メソッドを呼ぶ

```rust
let ss: &str = "str";

let s: String = String::from(ss);
```

`String` 型は `From` トレイトを実装し、本記事で使用している `String::from` メソッドの定義は以下の通りです。

```rust:from&nbsp;メソッドの定義
impl From<&str> for String {
    // ...
    #[inline]
    fn from(s: &str) -> String {
        s.to_owned()
    }
}
```

参考「[From&lt;&amp;'_ str&gt; - String in std::string - Rust](https://doc.rust-lang.org/std/string/struct.String.html#impl-From%3C%26%27_%20str%3E)」

## 1.4. `String::from` メソッドを呼ぶメソッド

```rust
let ss: &str = "str";

let s: String = ss.into();
// or
let s: String = ss.to_string();
```

`From` トレイトを実装する型があるとき、その逆の特性である `Into` トレイトが自動で実装されます。
これにより、`from` と `into` で逆の変換ができます。

```rust:Into&nbsp;トレイトのブランケット実装
impl<T, U> Into<U> for T
where
    U: From<T>,
{
    fn into(self) -> U {
        U::from(self)
    }
}
```

`&str` 型は `Into` トレイトをブランケット実装します。

```rust:into&nbsp;メソッドの定義&nbsp;(※理論上のソースコード)
impl Into<String> for &str {
    fn into(self) -> String {
        String::from(self)
    }
}
```

参考「[Into&lt;U&gt; - Into in std::convert - Rust](https://doc.rust-lang.org/std/convert/trait.Into.html#impl-Into%3CU%3E)」

`str` 型の `to_string` メソッドでは `String::from` メソッドを呼びます。

```rust:to_string&nbsp;メソッドの定義
impl ToString for str {
    #[inline]
    fn to_string(&self) -> String {
        String::from(self)
    }
}
```

参考「[ToString - str - Rust](https://doc.rust-lang.org/std/primitive.str.html#impl-ToString)」

## 1.5. `try_from` メソッドと `try_into` メソッド

`from` / `into` で型変換ができるということは、失敗する可能性のある型変換 `try_from` / `try_into` で型変換を試みて必ず成功するという特性を持つと考えられます。

```rust
let ss: &str = "str";

use std::convert::TryFrom;
let s: String = String::try_from(ss).unwrap();
// or
use std::convert::TryInto;
let s: String = ss.try_into().unwrap();
```

実際に、`TryFrom` トレイトと `TryInto` トレイトは以下のようにブランケット実装されます。

```rust:TryFrom&nbsp;トレイトのブランケット実装
impl<T, U> TryFrom<U> for T
where
    U: Into<T>,
{
    type Error = Infallible;

    fn try_from(value: U) -> Result<Self, Self::Error> {
        Ok(U::into(value))
    }
}
```

```rust:try_from&nbsp;メソッドの定義&nbsp;(※理論上のソースコード)
impl TryFrom<&str> for String {
    type Error = Infallible;

    fn try_from(value: &str) -> Result<Self, Self::Error> {
        Ok(<&str>::into(value))
    }
}
```

参考「[TryFrom&lt;U&gt; - String in std::string - Rust](https://doc.rust-lang.org/std/string/struct.String.html#impl-TryFrom%3CU%3E)」

```rust:TryInto&nbsp;トレイトのブランケット実装
impl<T, U> TryInto<U> for T
where
    U: TryFrom<T>,
{
    type Error = U::Error;

    fn try_into(self) -> Result<U, U::Error> {
        U::try_from(self)
    }
}
```

```rust:try_into&nbsp;メソッドの定義&nbsp;(※理論上のソースコード)
impl TryInto<String> for &str {
    type Error = String::Error;

    fn try_into(self) -> Result<String, String::Error> {
        String::try_from(self)
    }
}
```

参考「[TryInto in std::convert - Rust](https://doc.rust-lang.org/std/convert/trait.TryInto.html)」

## 1.6. `from_str` メソッドと `parse` メソッド

`from_str` / `parse` は文字列スライス `str` との変換に特化した `from` / `into` のような機能です。

```rust
let ss: &str = "str";

use std::str::FromStr;
let s: String = String::from_str(ss).unwrap();
// or
let s: String = ss.parse().unwrap();
```

`String` 型は `FromStr` トレイトを実装します。

```rust
impl FromStr for String {
    type Err = core::convert::Infallible;
    #[inline]
    fn from_str(s: &str) -> Result<String, Self::Err> {
        Ok(String::from(s))
    }
}
```

参考「[FromStr - String in std::string - Rust](https://doc.rust-lang.org/std/string/struct.String.html#impl-FromStr)」

`str::parse` メソッドは文字列 `str` 型から `FromStr` トレイトを実装する型に変換します。

```rust
impl str {
    // ...
    pub fn parse<F: FromStr>(&self) -> Result<F, F::Err> {
        FromStr::from_str(self)
    }
    // ...
}
```

参考「[parse - str - Rust](https://doc.rust-lang.org/std/primitive.str.html#method.parse)」

## 1.7. 文字列操作が目的の変換

Rust における文字列操作は `String` 型同士でも行えますが、文字列スライス `str` から直接文字列操作をするメソッドがあります。

```rust
let ss: &str = "str";

// 文字列置換を伴う型変換
let s_replaced: String = ss.replace("str", "String");
// or
let s_replaced: String = ss.replacen("str", "String", 1);

// 繰り返しを伴う型変換
let s_repeated: String = ss.repeat(3);

// 大文字・小文字変換を伴う型変換
let s_ascii_lowercase: String = ss.to_ascii_lowercase();
// or
let s_ascii_uppercase: String = ss.to_ascii_uppercase();
// or
let s_uppercase: String = ss.to_uppercase();
// or
let s_lowercase: String = ss.to_lowercase();
```

参考「[str - Rust](https://doc.rust-lang.org/std/primitive.str.html)」