Rustで複数のVecを連結(append, extendなど)
Rustで複数のベクタVec
を連結(結合)して一つのVec
にするには、append
やextend
メソッドを使う。
VecにVecを連結: append(引数に指定したVecは空になる)
append
メソッドは引数に指定したVec
のすべての要素を呼び出し元のVec
に追加する。引数に指定したVec
は空になる。
いずれのVec
もミュータブルでなければならない。
let mut v1 = vec![1, 2, 3];
let mut v2 = vec![4, 5, 6];
v1.append(&mut v2);
assert_eq!(v1, [1, 2, 3, 4, 5, 6]);
assert!(v2.is_empty());
VecにVecを連結: extend
extend
はExtend
トレイトのメソッド。Vec
にもExtend
トレイトが実装されている。
Vec
のextend
メソッドの引数にVec
を指定すると、すべての要素が呼び出し元のVec
に追加される。引数に指定したVec
の所有権は失われる。
let mut v1 = vec![1, 2, 3];
let v2 = vec![4, 5, 6];
v1.extend(v2);
assert_eq!(v1, [1, 2, 3, 4, 5, 6]);
// v2;
// error[E0382]: use of moved value: `v2`
所有権を失わせない例は後述。
Vecに配列やイテレータを連結
extend
メソッドの引数にはIntoIterator
トレイトを実装した型の値を指定できる。
Vec
だけでなく配列やスライスも指定可能。スライスだと一部の要素のみが追加される。
let mut v = vec![1, 2, 3];
let a = [4, 5, 6];
v.extend(a);
assert_eq!(v, [1, 2, 3, 4, 5, 6]);
let mut v1 = vec![1, 2, 3];
let v2 = vec![4, 5, 6];
v1.extend(&v2[1..]);
assert_eq!(v1, [1, 2, 3, 5, 6]);
イテレータをそのまま指定することもできる。map
などで処理した結果がそのまま追加される。
let mut v1 = vec![1, 2, 3];
let v2 = vec![4, 5, 6];
v1.extend(v2.iter().map(|x| x * 10));
assert_eq!(v1, [1, 2, 3, 40, 50, 60]);
所有権を失いたくない場合
クローンを渡す
当然ながら、クローンを渡せば元のVec
はそのまま。
let mut v1 = vec![1, 2, 3];
let v2 = vec![4, 5, 6];
v1.extend(v2.clone());
assert_eq!(v1, [1, 2, 3, 4, 5, 6]);
assert_eq!(v2, [4, 5, 6]);
要素がコピーできる型の場合、参照を渡す
要素がコピーできる型(Copy
トレイトを実装している型)の場合のExtend
トレイトも別に実装されている。
数値などのコピーできる型が要素の場合、参照を指定すると要素がコピーされる。
let mut v1 = vec![1, 2, 3];
let v2 = vec![4, 5, 6];
v1.extend(&v2);
assert_eq!(v1, [1, 2, 3, 4, 5, 6]);
assert_eq!(v2, [4, 5, 6]);
extend_from_sliceを使う
文字列String
などのコピーできない型が要素の場合は参照を指定するとエラーになるが、extend_from_slice
メソッドを使うと、要素がクローンされて呼び出し元に追加される。
引数はスライス&[T]
。Vec
の参照も指定可能。
let mut v1 = vec![String::from('a'), String::from('b'), String::from('c')];
let v2 = vec![String::from('d'), String::from('e'), String::from('f')];
// v1.extend(&v2);
// error[E0271]: type mismatch resolving ...
v1.extend_from_slice(&v2);
assert_eq!(v1, ["a", "b", "c", "d", "e", "f"]);
assert_eq!(v2, ["d", "e", "f"]);
配列の参照やスライスも指定できる。
let mut v = vec![String::from('a'), String::from('b'), String::from('c')];
let a = [String::from('d'), String::from('e'), String::from('f')];
v.extend_from_slice(&a);
assert_eq!(v, ["a", "b", "c", "d", "e", "f"]);
assert_eq!(a, ["d", "e", "f"]);
let mut v1 = vec![String::from('a'), String::from('b'), String::from('c')];
let v2 = vec![String::from('d'), String::from('e'), String::from('f')];
v1.extend_from_slice(&v2[1..]);
assert_eq!(v1, ["a", "b", "c", "e", "f"]);
assert_eq!(v2, ["d", "e", "f"]);
複数のVecを連結して新たなVecを生成: concat, join
複数のVec
を連結したい場合、append
やextend
を繰り返してもよいが、スライスのconcat
メソッドやjoin
メソッドを使う方法もある。
スライスのメソッドは型強制によって配列からも呼べるので、Vec
の配列([v1, v2, ...]
)からconcat
やjoin
を呼べばよい。append
やextend
のように既存のVec
に追加されるのではなく、新たなVec
が生成される。
なお、concat
, join
は文字列のベクタVec<String>
などを一つの文字列String
に連結するのにも使われる。
concat
concat
メソッドで複数のVec
を連結して新たなVec
を生成する例。
配列の要素に指定した時点で元のVec
の所有権は失われる。
let v1 = vec![1, 2, 3];
let v2 = vec![4, 5, 6];
let v3 = vec![7, 8, 9];
let v = [v1, v2, v3].concat();
assert_eq!(v, [1, 2, 3, 4, 5, 6, 7, 8, 9]);
// v1;
// error[E0382]: use of moved value: `v1`
参照を指定するとエラーになるが、明示的にスライスを指定することは可能。この場合、元のVec
はそのまま。
let v1 = vec![1, 2, 3];
let v2 = vec![4, 5, 6];
let v3 = vec![7, 8, 9];
// let v = [&v1, &v2, &v3].concat();
// error[E0599]: the method `concat` exists for array `[&std::vec::Vec<{integer}>; 3]`, but its trait bounds were not satisfied
let v = [&v1[..], &v2[..], &v3[..]].concat();
assert_eq!(v, [1, 2, 3, 4, 5, 6, 7, 8, 9]);
assert_eq!(v1, [1, 2, 3]);
assert_eq!(v2, [4, 5, 6]);
assert_eq!(v3, [7, 8, 9]);
let v = [&v1[1..], &v2[..], &v3[..2]].concat();
assert_eq!(v, [2, 3, 4, 5, 6, 7, 8]);
assert_eq!(v1, [1, 2, 3]);
assert_eq!(v2, [4, 5, 6]);
assert_eq!(v3, [7, 8, 9]);
concat
の内部ではextend_from_slice
が使われている。
join
join
メソッドは引数に指定したセパレータを間に挿入する。セパレータには参照を指定する必要がある。
let v1 = vec![1, 2, 3];
let v2 = vec![4, 5, 6];
let v3 = vec![7, 8, 9];
// let v = [v1, v2, v3].join(100);
// error[E0277]: the trait bound `[std::vec::Vec<{integer}>]: std::slice::Join<{integer}>` is not satisfied
let v = [v1, v2, v3].join(&100);
assert_eq!(v, [1, 2, 3, 100, 4, 5, 6, 100, 7, 8, 9]);
セパレータに配列やVec
を指定する場合は参照ではなく明示的にスライスを指定しなければならないので注意。
let v1 = vec![1, 2, 3];
let v2 = vec![4, 5, 6];
let v3 = vec![7, 8, 9];
// let v = [v1, v2, v3].join(&[100, 200]);
// error[E0277]: the trait bound `std::vec::Vec<{integer}>: std::borrow::Borrow<[[{integer}; 2]]>` is not satisfied
let v = [v1, v2, v3].join(&[100, 200][..]);
assert_eq!(v, [1, 2, 3, 100, 200, 4, 5, 6, 100, 200, 7, 8, 9]);
そのほかの使い方はconcat
と同じ。
let v1 = vec![1, 2, 3];
let v2 = vec![4, 5, 6];
let v3 = vec![7, 8, 9];
let v = [&v1[1..], &v2[..], &v3[..2]].join(&100);
assert_eq!(v, [2, 3, 100, 4, 5, 6, 100, 7, 8]);
assert_eq!(v1, [1, 2, 3]);
assert_eq!(v2, [4, 5, 6]);
assert_eq!(v3, [7, 8, 9]);