[Rust] 配列等から文字列のベクタ Vec<String> への変換とその仕組み

文字列の変換自体は別記事にしました。

参考「[[Rust] 文字列スライス str から文字列 String への変換とその仕組み - Qiita](https://qiita.com/kerupani129/items/89f31bab79ebba43aeb4)」

# 0. まとめ

- 文字列スライス `&str`
- 文字列 `String`

```rust:要素の型が文字列スライス&nbsp;&amp;str&nbsp;の場合
let array = ["foo", "bar", "baz"]; // 配列やベクタ、スライス等

let vec: Vec<String> = array.iter().map(|&s| s.to_string()).collect(); // |s| でなく |&s| 推奨 (※理由は後述)
// or
let vec: Vec<String> = array.iter().map(|&s| String::from(s)).collect();
// or
let vec: Vec<String> = array.iter().map(|&s| s.into()).collect();
// or
let vec: Vec<String> = array.iter().map(|&s| s.to_owned()).collect();

// 確認
assert_eq!(
    vec,
    vec!["foo".to_string(), "bar".to_string(), "baz".to_string()]
);
```

```rust:要素の型が文字列以外の場合
let array = [10, 20, 30]; // 配列やベクタ、スライス等

let vec: Vec<String> = array.iter().map(|x| x.to_string()).collect(); // メモ: i8, u8 等では |x| でなく |&x| 推奨 (※理由は後述)

// 確認
assert_eq!(vec, vec![10.to_string(), 20.to_string(), 30.to_string()]);
```

# 1. データ変換の流れ

```rust:配列等の要素の型が文字列スライス&nbsp;&amp;str&nbsp;の場合
["foo", "bar", "baz"]                        : [&str; 3];
["foo", "bar", "baz"].iter()                 : Iter<&str>;
["foo", "bar", "baz"].iter().map(f)          : Map<Iter<&str>, {{closure}}>;
["foo", "bar", "baz"].iter().map(f).collect(): Vec<String>;
```

```rust:配列等の要素の型が文字列以外の場合
[10, 20, 30]                        : [i32; 3];
[10, 20, 30].iter()                 : Iter<i32>;
[10, 20, 30].iter().map(f)          : Map<Iter<i32>, {{closure}}>;
[10, 20, 30].iter().map(f).collect(): Vec<String>;
```

1. 型強制によって、入力の型が配列等の場合もスライスのメソッドを呼べる
1. スライスから `Iter` 型のイテレータに変換
1. `Iterator::map` メソッドで `Iter` 型のイテレータから `Map` 型のイテレータに変換
1. `Iterator::collect` メソッドで `Map` 型のイテレータから `Vec<String>` に変換

## 1.1. 型強制によるスライスへの自動型変換

配列からスライスへの Unsized 型強制や、メソッド呼び出し時の型強制等については別記事にしました。

参考「[[Rust] 配列やベクタが自動でスライスに変換される仕組み - Qiita](https://qiita.com/kerupani129/items/17584274379f0c65fc34)」
参考「[[Rust] メソッド呼び出し時におけるメソッド探索の仕組み: 自動参照 & 自動参照外し及び Unsized 型強制 - Qiita](https://qiita.com/kerupani129/items/8dba9f5bb2c009c4d08d)」

`let` 文や関数引数等で行われる型強制とメソッド呼び出しによる型強制は仕組みが異なりますが、「Unsized 型強制」や「Deref 型強制」自体は同じで、配列やベクタ等はスライスに型強制されます。

- `[&str; N]` -> `[&str]`: Unsized 型強制
- `Vec<&str>` -> `[&str]`: Deref 型強制

※ Unsized 型強制はメソッド呼び出しではそのまま行われますが、`let` 文や関数引数等では参照などの「ポインタのような」型 (`&[&str; N]` 等) であ必要があります。

## 1.2. スライスからイテレータへ変換

スライスの `iter` メソッドを使用して、スライス用のイテレータの実装である (`Iterator` トレイトを実装する) `Iter` 型に変換します。

1. `[&str]` -> `&[&str]`: メソッド呼び出し時の自動参照
1. `&[&str]` -> `Iter<&str>`: `iter` メソッドによる変換

```rust:iter&nbsp;メソッドの定義
impl<T> [T] {
    // ...
    pub fn iter(&self) -> Iter<'_, T> {
        // ...
    }
    // ...
}
```

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

```rust
let array = ["foo", "bar", "baz"];

use std::slice::Iter;
let iter: Iter<&str> = array.iter();
```

## 1.3. `Iter` 型は `Iterator` トレイトを実装

`std::slice::Iter` 型は `core::slice::iter::iterator` マクロを用いて `Iterator` トレイトを実装します。

```rust:iterator&nbsp;マクロの定義
macro_rules! iterator {
    (
        struct $name:ident -> $ptr:ty,
        $elem:ty,
        $raw_mut:tt,
        {$( $mut_:tt )?},
        {$($extra:tt)*}
    ) => {
        // ...
        impl<'a, T> Iterator for $name<'a, T> {
            type Item = $elem;
            // ...
        }
        // ...
    }
}
```

```rust:Iter&nbsp;型の実装の一部
iterator! {struct Iter -> *const T, &'a T, const, {/* no mut */}, {
    // ...
}}
```

マクロの引数の値は以下のようになります。

- `$name = Iter`
- `$elem = &'a T`

```rust:Iter&nbsp;型は&nbsp;Iterator&nbsp;トレイトを実装&nbsp;(※理論上のソースコード)
impl<'a, T> Iterator for Iter<'a, T> {
    type Item = &'a T;
    // ...
}
```

`type T = &str;` とすると、`<Iter as Iterator>::Item` は `&&str` 型になります (本記事ではライフタイムの説明略) 。

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

## 1.4. `map` メソッドによるイテレータから別のイテレータへ変換

`map` は他のプログラミング言語でも取り入れられることが多い機能で、イテレータの各要素を別の値に変換し、同じ長さで変換された要素を持つ別のイテレータに変換します。

```rust:map&nbsp;メソッドの定義
pub trait Iterator {
    // ...
    type Item;
    // ...
    fn map<B, F>(self, f: F) -> Map<Self, F>
    where
        Self: Sized,
        F: FnMut(Self::Item) -> B,
    {
        // ...
    }
    // ...
}
```

参考「[map - Iterator in std::iter - Rust](https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.map)」

Rust の場合は一度 `Iterator` トレイトを実装する `Map` 型に変換し、要素を変換するクロージャをラップし、要素の値を得ようとした段階で変換が行われます (遅延評価) 。

```rust:Map&nbsp;型の&nbsp;next&nbsp;メソッドの定義
impl<B, I: Iterator, F> Iterator for Map<I, F>
where
    F: FnMut(I::Item) -> B,
{
    type Item = B;
    // ...
    fn next(&mut self) -> Option<B> {
        self.iter.next().map(&mut self.f)
    }
    // ...
}
```

※ `self.iter.next().map` の `map` は `Option<I::Item>` 型が持つメソッドで、イテレータの `map` メソッドとは別物です (本記事では不明略) 。

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

```rust
let array = ["foo", "bar", "baz"];

use std::slice::Iter;
let iter: Iter<&str> = array.iter();

let f = |&s: &&str| s.to_string(); // ※文字列の変換については後述

use std::iter::Map;
let map: Map<Iter<&str>, _> = iter.map(f);
```

ここでは文字列スライスから文字列に変換することが目的なので、関数 `f` は `&&str` から `String` へ変換する関数です。

`Map<Iter<&str>, _>` のジェネリクスは以下のように解決されます。

- `type I = Iter<&str>;`
- `type I::Item = &&str;`
- `type B = String;`
- `type Item = String;`

※関数がクロージャの場合、一意で匿名 (ユニークでアノニマス) な型になるため、型名を表現することはできません。

参考「[Closure types - The Rust Reference](https://doc.rust-lang.org/reference/types/closure.html)」

## 1.5. イテレータは `IntoIterator` トレイトをブランケット実装

`IntoIterator` トレイトは「イテレータへ変換できる特性」で、イテレータ自身もブランケット実装します。

```rust:IntoIterator&nbsp;トレイトをブランケット実装
impl<I: Iterator> IntoIterator for I {
    type Item = I::Item;
    type IntoIter = I;

    #[inline]
    fn into_iter(self) -> I {
        self
    }
}
```

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

参考「[Using Trait Bounds to Conditionally Implement Methods - Traits: Defining Shared Behavior - The Rust Programming Language](https://doc.rust-lang.org/book/ch10-02-traits.html#using-trait-bounds-to-conditionally-implement-methods)」(「トレイト境界を使用して、メソッド実装を条件分けする」「ブランケット実装」)

`I: Iterator` (`I` 型は `Iterator` トレイトを実装) かつ `iter: I` (変数 `iter` は `I` 型) のとき `iter.into_iter()` の戻り値の型も `I` 型になります。

```rust
use std::slice::Iter;

let foo: Iter<i32> = [10, 20, 30].iter();

let bar: Iter<i32> = foo.into_iter();
```

`Iterator` トレイトを実装する `Map` 型も `IntoIterator` トレイトをブランケット実装します。

## 1.6. ベクタ `Vec` は `FromIterator` トレイトを実装

`FromIterator` トレイトは「イテレータから変換できる特性」です。

`IntoIterator` トレイトを実装する型、すなわち「イテレータ自身を含むイテレータに変換可能な型」から `Self` 型に変換する機能を持ちます。

```rust:FromIterator&nbsp;トレイトの定義
pub trait FromIterator<A>: Sized {
    // ...
    fn from_iter<T: IntoIterator<Item = A>>(iter: T) -> Self;
}
```

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

ベクタ `Vec` は `FromIterator` トレイトを実装します。

```rust
impl<T> FromIterator<T> for Vec<T> {
    // ...
    fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Vec<T> {
        // ...
    }
}
```

参考「[FromIterator&lt;T&gt; - Vec in std::vec - Rust](https://doc.rust-lang.org/std/vec/struct.Vec.html#impl-FromIterator%3CT%3E)」

```rust
use std::slice::Iter;
let foo: Iter<i32> = [10, 20, 30].iter();

use std::iter::FromIterator;
let bar: Vec<&i32> = Vec::<&i32>::from_iter(foo);
```

## 1.7. イテレータからベクタへ変換

イテレータの `collect` メソッドは、自身のイテレータを `FromIterator` トレイトを実装する型へ変換します。

変換の際に `FromIterator::from_iter` メソッドを呼んでいます。

```rust:collect&nbsp;メソッドのデフォルト実装
pub trait Iterator {
    // ...
    type Item;
    // ...
    fn collect<B: FromIterator<Self::Item>>(self) -> B
    where
        Self: Sized,
    {
        FromIterator::from_iter(self)
    }
    // ...
}
```

参考「[collect - Iterator in std::iter - Rust](https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.collect)」

```rust
let array = ["foo", "bar", "baz"];

use std::slice::Iter;
let iter: Iter<&str> = array.iter();

let f = |&s: &&str| s.to_string(); // ※文字列の変換については後述

use std::iter::Map;
let map: Map<Iter<&str>, _> = iter.map(f);

let vec: Vec<String> = map.collect();
```

ここで、`map.collect()` のジェネリクスは以下のように解決されます。

- `type Item = String;`
- `type B = Vec<String>;`

メソッド呼び出しを繋げると、以下のようになります。

```rust
let array = ["foo", "bar", "baz"];

// ※ map メソッドに渡すクロージャの中身については後述
let vec: Vec<String> = array.iter().map(|&s: &&str| s.to_string()).collect();
```

# 2. 文字列 `String` に変換する方法

## 2.1. 文字列スライス `str` から文字列 `String` の変換

Rust における文字列スライス `str` から文字列 `String` の変換は主に以下の 4 つです。

(※他にも、大文字や小文字に変換するメソッド等もあります。)

`s: &str` のとき:

- `s.to_string()`
- `String::from(s)`
- `s.into()`
- `s.to_owned()`

詳細は別記事にしました。

参考「[[Rust] 文字列スライス str から文字列 String への変換とその仕組み - Qiita](https://qiita.com/kerupani129/items/89f31bab79ebba43aeb4)」

## 2.2. 文字列以外から文字列 `String` の変換

フォーマットを指定せずに単に文字列に変換したい場合には `to_string` メソッドを使用します。

## 2.3. `to_string` メソッドの注意

`to_string` メソッドでは自動参照外しされません。

参考「[[Rust] to_string メソッド等は呼び出し時に自動参照外しされない - Qiita](https://qiita.com/kerupani129/items/eaf16e41bc1786a6d049)」

これにより、`&str` と `&&str` で呼ばれる `to_string` が異なる (文字列に変換する具体的な処理が異なる) 等が起きます (バージョン 1.55.0 現在) 。

参考「[[Rust] &str と &&str で呼ばれる to_string メソッドが異なる - Qiita](https://qiita.com/kerupani129/items/2f61c2f76803c49dede3)」

`str` 以外でも同様の現象が起きることがあります。

- `char`, `str`, `String`
- `Cow<str>`
- `i8`, `u8`

参考「[Implementors - ToString in std::string - Rust](https://doc.rust-lang.org/std/string/trait.ToString.html#implementors)」(`ToString` トレイトを独自に実装する型等)

処理速度を気にするのであれば、**明示的に参照外し**をするか、**型を修飾してメソッドを呼ぶ**方が良いです。

# 3. 文字列 `String` に変換する関数またはクロージャを定義

`Iter` ではイテレータの要素の型に参照が付きます。

例:

- `type <Iter<&str> as Iterator>::Item = &&str;`
- `type <Iter<i32> as Iterator>::Item = &i32;`

## 3.1. `to_string` メソッドを使用する場合

`to_string` メソッドは明示的な参照外しをしなくても**コンパイルエラーになりませんが**、前述の通り、型が独自に `ToString` トレイトを実装している場合を考えて**明示的に参照外し**するか**型を修飾**します。

関数やメソッドの引数において「パターン」を用いて参照外しすることができます。

参考「[[Rust] 「パターン」を用いた非構造化変数束縛 - Qiita](https://qiita.com/kerupani129/items/f30596eed4e5b2ca7cd1)」

```rust
// &str の場合
let f = |&s: &&str| s.to_string(); // 参照パターンによる参照外し
// or
let f = |s: &&str| (*s).to_string(); // 参照外し演算子 * による参照外し
// or
let f = |s: &&str| str::to_string(s); // 型を修飾して自動参照外し
// or
let f = |s: &&str| <str as ToString>::to_string(s); // 完全修飾構文で自動参照外し
// etc.

// i32 の場合
let f = |x: &i32| x.to_string();
```

※ `Iterator::map` メソッドの引数に直接クロージャを書く場合は、クロージャの引数の型を省略できます。

## 3.2. `String::from` メソッドや `<&str>::into` メソッドを使用する場合

`from` と `into` は対応する機能です。

どちらもジェネリック型を使用していて、その型を解決できる必要があります。
`&&str` から変換しようとするとジェネリクスを解決できず、コンパイルエラーになります。

**明示的に参照外し**するか**型を修飾**して対応します。

```rust:from&nbsp;を使用する場合
let f = |&s: &&str| String::from(s); // 参照パターンによる参照外し
// or
let f = |s: &&str| String::from(*s); // 参照外し演算子 * による参照外し
// or
let f = |s: &&str| -> String { From::<&str>::from(s) }; // 型を修飾して自動参照外し
// or
let f = |s: &&str| <String as From<&str>>::from(s); // 完全修飾構文で自動参照外し
// etc.
```

```rust:into&nbsp;を使用する場合
let f = |&s: &&str| -> String { s.into() }; // 参照パターンによる参照外し
// or
let f = |s: &&str| -> String { (*s).into() }; // 参照外し演算子 * による参照外し
// or
let f = |s: &&str| -> String { <&str>::into(s) }; // 型を修飾して自動参照外し
// or
let f = |s: &&str| -> String { <&str as Into<_>>::into(s) }; // 型を修飾して自動参照外し
// or
let f = |s: &&str| <&str as Into<String>>::into(s); // 完全修飾構文で自動参照外し
// etc.
```

※ `Iterator::map` メソッドの引数に直接クロージャを書く場合は、クロージャの引数の型や戻り値の型を省略できます。

## 3.3. `str::to_owned` メソッドを使用する場合

`ToOwned` トレイトは参照に対して再帰的にブランケット実装され、実装している型によって戻り値の型が異なるため、**明示的に参照を外す**か**型を修飾**しないとコンパイルエラーになります。

※ `ToOwned::to_owned` メソッドの戻り値の型は `Self` でなく `Self::Owned` のため、戻り値の型から `self` の型を決定できません。

参考「[[Rust] to_string メソッド等は呼び出し時に自動参照外しされない - Qiita](https://qiita.com/kerupani129/items/eaf16e41bc1786a6d049)」

```rust
let f = |&s: &&str| s.to_owned(); // 参照パターンによる参照外し
// or
let f = |s: &&str| (*s).to_owned(); // 参照外し演算子 * による参照外し
// or
let f = |s: &&str| str::to_owned(s); // 型を修飾して自動参照外し
// or
let f = |s: &&str| <str as ToOwned>::to_owned(s); // 完全修飾構文で自動参照外し
// etc.
```

※ `Iterator::map` メソッドの引数に直接クロージャを書く場合は、クロージャの引数の型を省略できます。