Rustで文字列String, &strを連結(format!, push_strなど)
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
String
のpush_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);
}
}
a += b
はa.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
}
}
a + b
はa.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
や+=
演算子などで別の文字列を追加していくこともできる。
空のString
はString::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
, push
はString
のメソッドなので、&str
からは使えない。また、&str
を左オペランドとする+
, +=
演算子は定義されておらず使えない。
文字列スライス&str
を先頭として文字列を連結したい場合、先頭の&str
をString
に変換する必要がある。
&str
はString::from
やto_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");