rs.nkmk.me

Rustで文字列String, &strを連結(format!, push_strなど)

Posted: | Tags: Rust, 文字列

Rustで文字列Stringや文字列スライス&strを連結(結合)するには、format!マクロや、push_str+, +=演算子などを使う。

文字列のベクタVec<String>などを一つの文字列Stringに連結する方法については以下の記事を参照。

String, &strを連結してStringを生成: format!

format!マクロを使うと、複数のString&strを連結して新たなStringを生成できる。

第一引数の文字列リテラル内のプレースホルダー{}に第二引数以降の値が挿入される。新たなStringが生成され、元のString, &strはそのまま。

let s_string = String::from("abc");
let s_str = "XYZ";

let s = format!("{}_123_{}", s_string, s_str);
assert_eq!(s, "abc_123_XYZ");
assert_eq!(s_string, "abc");
assert_eq!(s_str, "XYZ");

String同士や&str同士でも問題ない。3個以上の場合も同様。

シンプルに連結したい場合は第一引数を"{}{}"のようにすればよい。

let s = format!("{}{}", s_string, s_str);
assert_eq!(s, "abcXYZ");

文字charも扱える。{}内に変数名を直接記述することも可能。

let c = '@';
let s = format!("{s_string}{c}{s_str}");
assert_eq!(s, "abc@XYZ");

既存のStringにString, &strを連結

format!マクロは新たなStringを生成するが、既存のStringに別のString, &strを連結することもできる。

push_str

Stringpush_strメソッドを使う。

push_strメソッドの引数は文字列スライス&str。呼び出し元のStringはミュータブルでなければならないので注意。

let mut s_string = String::from("abc");
let s_str = "XYZ";

s_string.push_str(s_str);
assert_eq!(s_string, "abcXYZ");
assert_eq!(s_str, "XYZ");

&strではなくStringを連結したい場合は、参照を指定する。

let mut s_string1 = String::from("abc");
let s_string2 = String::from("XYZ");

s_string1.push_str(&s_string2);
assert_eq!(s_string1, "abcXYZ");
assert_eq!(s_string2, "XYZ");

push_strは破壊的処理。元のStringをそのまま残しておきたい場合は、cloneでクローンを生成してpush_strを実行すればよい。

let s_string = String::from("abc");
let s_str = "XYZ";

let mut s_clone = s_string.clone();
s_clone.push_str(s_str);
assert_eq!(s_clone, "abcXYZ");
assert_eq!(s_string, "abc");
assert_eq!(s_str, "XYZ");

以降で説明するpushや、内部でpush_strを使用する+=, +演算子でも同様。元のStringを残したい場合はcloneを使う。上述のformat!マクロを使ってもよい。

push

Stringに文字列ではなく文字charを連結したい場合はpushメソッドを使う。

let mut s_string = String::from("abc");
let c = '!';

s_string.push(c);
assert_eq!(s_string, "abc!");
assert_eq!(c, '!');

シングルクォーテーション'で囲むと文字charになるが、同じ1文字でもダブルクォーテーション"で囲むと文字列&strになる。その場合はpushではなくpush_strを使う。

let mut s_string = String::from("abc");
let s_str = "!";

s_string.push_str(s_str);
assert_eq!(s_string, "abc!");
assert_eq!(s_str, "!");

+=演算子

Stringに対する+=演算子はpush_strメソッドと等価。

impl AddAssign<&str> for String {
    #[inline]
    fn add_assign(&mut self, other: &str) {
        self.push_str(other);
    }
}
source: string.rs

a += ba.push_str(b)と等価。左オペランドaはミュータブルなStringで右オペランドb&str(またはStringの参照)でなければならない。

let mut s_string = String::from("abc");
let s_str = "XYZ";

s_string += s_str;
assert_eq!(s_string, "abcXYZ");
assert_eq!(s_str, "XYZ");
let mut s_string1 = String::from("abc");
let s_string2 = String::from("XYZ");

s_string1 += &s_string2;
assert_eq!(s_string1, "abcXYZ");
assert_eq!(s_string2, "XYZ");

+演算子

Stringに対する+演算子でも、内部でpush_strメソッドが使われている。

impl Add<&str> for String {
    type Output = String;

    #[inline]
    fn add(mut self, other: &str) -> String {
        self.push_str(other);
        self
    }
}
source: string.rs

a + ba.push_str(b)としてからaを返す。左オペランドaはミュータブルなStringで右オペランドb&str(またはStringの参照)でなければならない。

左オペランドの変数の所有権は移動し失われるので注意。

let s_string = String::from("abc");
let s_str = "XYZ";

let s = s_string + s_str;
assert_eq!(s, "abcXYZ");
assert_eq!(s_str, "XYZ");

// assert_eq!(s_string, "abc");
// error[E0382]: borrow of moved value: `s_string`
let s_string1 = String::from("abc");
let s_string2 = String::from("XYZ");

let s = s_string1 + &s_string2;
assert_eq!(s, "abcXYZ");
assert_eq!(s_string2, "XYZ");

// assert_eq!(s_string1, "abc");
// error[E0382]: borrow of moved value: `s_string1`

空のStringに追加

空のStringを生成して、push_str+=演算子などで別の文字列を追加していくこともできる。

空のStringString::newまたはString::with_capacityで生成可能。

let s_string = String::from("abc");
let s_str = "XYZ";

let mut s = String::new();
s.push_str(&s_string);
s.push_str(s_str);
assert_eq!(s, "abcXYZ");

let mut s = String::with_capacity(100);
s.push_str(&s_string);
s.push_str(s_str);
assert_eq!(s, "abcXYZ");

String::with_capacityは容量capacityを確保して空のStringを生成する。最終的なデータ量の目安が分かっている場合は、String::with_capacityを使うと余計な再割り当てを避けることができる。

Stringにおけるcapacityは文字数ではなくバイト数単位なので注意。capacityについては以下の記事を参照。

&strにString, &strを連結したい場合

push_str, pushStringのメソッドなので、&strからは使えない。また、&strを左オペランドとする+, +=演算子は定義されておらず使えない。

文字列スライス&strを先頭として文字列を連結したい場合、先頭の&strStringに変換する必要がある。

&strString::fromto_stringなどでStringに変換できる。

let s_str = "abc";
let s_string = String::from("XYZ");

let mut s_str_string = String::from(s_str);
s_str_string.push_str(&s_string);
assert_eq!(s_str_string, "abcXYZ");

let s = String::from(s_str) + &s_string;
assert_eq!(s, "abcXYZ");

空のStringを生成してから追加していく場合や、format!を使う場合は、&strが先頭でも問題ない。

let s_str = "abc";
let s_string = String::from("XYZ");

let mut s = String::new();
s.push_str(s_str);
s.push_str(&s_string);
assert_eq!(s, "abcXYZ");

let s = format!("{}{}", s_str, s_string);
assert_eq!(s, "abcXYZ");

関連カテゴリー

関連記事