LoginSignup
94
69

More than 1 year has passed since last update.

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

Last updated at Posted at 2020-07-04

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

charとStringと&strの関係

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

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

Stringと&strの関係

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

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

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

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

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

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メソッドが使える。

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

Vec<char>をStringに変換

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

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>に変換してみる。

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>に変換することも同様の方法で可能。

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()でいける。

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

String に charを追加する

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

&str に char を追加したい

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

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で追記が可能。

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()も使える。

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するという手もある、冗長だけど。

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を作成する。

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()使った方がシンプルな感じがする。

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()を使う方法を教えていただきました。この方法も良いですね。

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の書きかた・作りかた』という本を書きました。良かったらそちらも見てみてください!!

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

94
69
4

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
94
69