Rustのcharと&strとStringが難しい

RustのcharとStringと&strがすごく難しい。さすが学習難易度が高いRust。それでも、たぶん慣れの問題で、覚えて慣れるのが良い方法かも。


# charとStringと&strの関係

Rustでは、Stringと&strがたくさん出てくる。この三者の違いを一言で語ってみよう。

 - ``String``は文字列を表すことができる。
 - ``&str``はUTF-8の配列のスライス(&[u8])であり文字列リテラルを表すのに使われる。
 - ``char``はユニコードの1文字を表現できる。


# Stringと&strの関係

文字列リテラルは&strである。

```rust:prints.rs
let s1: &str = "abc";
println!("{}", s1); // abc
```

Stringと&strは容易に変換が可能。

```rust:s2s.rs
// &str → String
let s1: String = String::from("abc");
println!("{}", s1);
```

&str → String → &strと変換する場合。

```rust:sss.rs
    let s1: &str = "abc";
    let s2: String = String::from(s1); // &str -> String
    let s3: &str = &s2; // String -> &str
    println!("{}", s3);
```

このように、&strとStringは比較的簡単に変換できる。

# charをStringに変換

charをStringに変換するには、to_stringメソッドが使える。

```rust:c2s.rs
    let c: char = 'a';
    let cs: String = c.to_string();
    println!("{}", &cs); // → a
```

# Vec＜char＞をStringに変換

サイズ可変な配列であるcharのベクタ型であるVec＜char＞。これをStringに変換するには、iter().collect()を使う。

```rust:vec2s.rs
// Vec<char>を初期化
let c = vec!['a', 'b', 'c'];
// Vec<char>をStringに変換
let cs: String = c.iter().collect();
println!("{}", &cs); // → abc
```

# Stringや&strをVec＜char＞に変換

&strをVec＜char＞に変換してみる。

```rust:s2vec.rs
// &str → Vec<char>
let cs: Vec<char> = "abcd".chars().collect();
// Vec<char>であれば、添字アクセス可能
let c1: char = cs[0];
let c2: char = cs[1];
println!("{}-{}", c1.to_string(), c2.to_string());
```

同じように、StringをVec＜char＞に変換することも同様の方法で可能。

```rust:s2vec2.rs
    let s = String::from("abc");
    let cs: Vec<char> = s.chars().collect();
    let c1: char = cs[0];
    println!("{}", c1.to_string());
```

&[char]をStringに変換する場合も、iter().collect()でいける。

```rust:vec2s2.rs
    let cs: &[char] = &['a', 'b', 'c'];
    let s: String = cs.iter().collect();
    println!("{}", s); // abc
```

# String に charを追加する

```rust:append.rs
    let mut s = String::from("abc");
    s.push('d');
    println!("{}", s); // abcd
```

# &str に char を追加したい

&strは残念ながら変更できないので一度Stringにしてからcharを追加する。

```rust:append2.rs
    let s = "abc";
    let mut ss = String::from(s);
    ss.push('d');
    println!("{}", ss); // abcd
```

# Vec＜char＞とVec＜char＞を足す

mut Vec＜char＞であれば、extendで追記が可能。

```rust:append3.rs
    let mut a: Vec<char> = "abc".chars().collect();
    let b: Vec<char> = "def".chars().collect();
    a.extend(b.iter()); // bの内容をaに追加
    let c: String = a.iter().collect();
    println!("{}", c); // abcdef
```

似たような感じだけど、Vec.append()も使える。

```rust:append3a.rs
    let mut a: Vec<char> = "abc".chars().collect();
    let b: Vec<char> = "def".chars().collect();
    a.append(&mut b.clone());
    println!("{}", a.iter().collect::<String>()); // abcdef
```

Stringに変換してconcatするという手もある、冗長だけど。

```rust:append4.rs
    let a: Vec<char> = "abc".chars().collect();
    let b: Vec<char> = "def".chars().collect();
    let c: String = [
        a.iter().collect::<String>(),
        b.iter().collect::<String>()
    ].concat();
    println!("{}", c); // abcdef
```

上記で、Vec＜char＞のaとbの内容を変更したくない場合は、新しい変数cを作成する。

```rust:append5.rs
    let a = "abc".chars().collect::<Vec<char>>();
    let b = "def".chars().collect::<Vec<char>>();
    // c = a + b
    let mut c: Vec<char> = Vec::new();
    c.append(&mut a.clone());
    c.append(&mut b.clone());
    // print(c)
    let s = c.iter().collect::<String>();
    println!("{}", s); // abcdef
```

上記と全く同じで別の方法。好みにもよるけど、extend()使った方がシンプルな感じがする。

```rust:append6.rs
    let a = "abc".chars().collect::<Vec<char>>();
    let b = "def".chars().collect::<Vec<char>>();
    // c = a + b
    let mut c: Vec<char> = Vec::new();
    c.extend(a.iter());
    c.extend(b.iter());
    // print(c)
    let s = c.iter().collect::<String>();
    println!("{}", s); // abcdef
```

コメントで、chain()を使う方法を教えていただきました。この方法も良いですね。

```rust:append7.rs
    let a = "abc".chars().collect::<Vec<char>>();
    let b = "def".chars().collect::<Vec<char>>();

    // String が必要な場合
    let s = a.iter().chain(b.iter()).collect::<String>();
    println!("{}", s); // abcdef

    // Vec<&char> が必要な場合
    let c = a.iter().chain(b.iter()).collect::<Vec<&char>>();
    println!("{:?}", c); // ['a', 'b', 'c', 'd', 'e', 'f']
    
    // Vec<char>が必要で、aとbの所有権を奪う場合
    let d: Vec<char> = a.into_iter().chain(b.into_iter()).collect();
    println!("{:?}", d); // ['a', 'b', 'c', 'd', 'e', 'f']
```

## 参考

[『Rustの書きかた・作りかた』](https://amzn.to/3mnx9qe)という本を書きました。良かったらそちらも見てみてください！!

https://www.amazon.co.jp/dp/4802613512/ref=as_sl_pc_tf_til?tag=text2musiccom-22&linkCode=w00&linkId=97170724c87fa892e4a05732776c9586&creativeASIN=4802613512


その他、文字列操作で役立つリンク

 - 文字列について -- https://qiita.com/aflc/items/f2be832f9612064b12c6
 - 置換と正規表現 -- https://qiita.com/scivola/items/60141f262caa53983c3a