Question
I want to combine two vectors in Rust into a single vector.
For example, I have:
let mut a = vec![1, 2, 3];
let b = vec![4, 5, 6];
for val in &b {
a.push(*val);
}
Is concatenating vectors in Rust possible in a more elegant or idiomatic way? If so, what is the best approach?
Short Answer
By the end of this page, you will understand how to concatenate vectors in Rust, when to use append, extend, or iterator-based approaches, and how Rust's ownership and borrowing rules affect each option.
Concept
In Rust, concatenating vectors means taking elements from one collection and adding them to another. This is very common when building lists of results, combining data from multiple sources, or preparing values for later processing.
The main thing that makes Rust slightly different from some other languages is ownership. When you combine vectors, Rust needs to know:
- Are you moving elements from one vector into another?
- Are you copying elements?
- Do you want to keep the original vector intact?
Because of that, Rust provides multiple good solutions, each useful in a different situation.
The main options
-
a.append(&mut b)- Moves all elements from
bintoa bbecomes empty afterward- Usually the most efficient choice when you no longer need
b
- Moves all elements from
-
a.extend(b)- Consumes
band moves its elements intoa bcannot be used afterward- Clean and idiomatic when ownership transfer is fine
- Consumes
-
a.extend(&b)or
Mental Model
Think of a vector like a box holding items.
appendis like pouring all items from box B into box A. Box B ends up empty.extend(b)is like handing box B over so its items can be transferred into box A. You give up B.extend(&b)or cloning is like making copies of the items in box B and placing the copies into box A. Box B stays unchanged.
The important question is: Do you want to move the original items, or keep them and make copies?
That one decision usually tells you which method to choose.
Syntax and Examples
Core syntax
1. Move all elements and empty the second vector
let mut a = vec![1, 2, 3];
let mut b = vec![4, 5, 6];
a.append(&mut b);
println!("a = {:?}", a); // [1, 2, 3, 4, 5, 6]
println!("b = {:?}", b); // []
Use this when:
- you no longer need
b - you want an efficient in-place operation
2. Consume the second vector with extend
let mut a = vec![1, 2, 3];
let b = vec![4, , ];
a.(b);
(, a);
Step by Step Execution
Consider this example:
let mut a = vec![1, 2, 3];
let mut b = vec![4, 5, 6];
a.append(&mut b);
Step-by-step
ais created as[1, 2, 3].bis created as[4, 5, 6].a.append(&mut b)is called.- Rust takes all elements from
band moves them intoa. - After the call:
abecomes[1, 2, 3, 4, 5, 6]bbecomes[]
Another example with
Real World Use Cases
Concatenating vectors shows up often in Rust applications.
Combining API results
If you fetch paginated results from an API, each page may return a Vec<Item>. You often append each page into one final vector.
all_items.append(&mut page_items);
Collecting validation errors
A form validator may gather errors from several checks and combine them into one list.
errors.extend(name_errors);
errors.extend(email_errors);
Merging log entries
A program might collect log entries from different modules and merge them into one ordered list for output or storage.
Processing files in batches
If several worker functions each return Vec<PathBuf> or Vec<String>, you can combine them into one vector for later processing.
Building command-line output
A CLI tool may gather results from multiple filters and combine them before printing or exporting.
Real Codebase Usage
In real Rust codebases, developers usually choose between append, extend, and iterator chains based on ownership and performance.
Common patterns
In-place accumulation
A very common pattern is to create one result vector and keep extending it:
let mut results = Vec::new();
results.extend(source_one());
results.extend(source_two());
This is simple and readable.
Efficient draining of temporary vectors
If a helper function returns a temporary vector that is only needed once, append is useful:
let mut all = Vec::new();
let mut batch = load_batch();
all.append(&mut batch);
This avoids unnecessary cloning.
Preserving inputs
Common Mistakes
1. Pushing references instead of values
Broken code:
let mut a = vec![1, 2, 3];
let b = vec![4, 5, 6];
for val in &b {
a.push(val);
}
Why it fails:
valis&i32a.push(...)expectsi32
Fix:
for val in &b {
a.push(*val);
}
Or more idiomatically:
a.extend(&b);
2. Using append without making the second vector mutable
Comparisons
| Approach | Keeps second vector? | Moves values? | Requires Clone/Copy? | Typical use |
|---|---|---|---|---|
a.append(&mut b) | Yes, but empties it | Yes | No | Fast in-place merge when b can become empty |
a.extend(b) | No | Yes | No | Clean merge when b is no longer needed |
a.extend(&b) | Yes | No, copies from references | T: Copy in practice for owned result |
Cheat Sheet
// Move all items from b into a; b becomes empty
let mut a = vec![1, 2];
let mut b = vec![3, 4];
a.append(&mut b);
// Move items from b into a; b is consumed
let mut a = vec![1, 2];
let b = vec![3, 4];
a.extend(b);
// Keep b and copy values (good for Copy types like i32)
let mut a = vec![1, 2];
let b = vec![3, 4];
a.extend(&b);
// Keep b and clone values (good for String and other Clone types)
let mut a = vec![String::()];
= [::()];
a.(b.().());
= [, ];
= [, ];
: <_> = a.().(b.()).();
FAQ
Can you concatenate vectors in Rust?
Yes. Common idiomatic ways include append, extend, and iterator chaining with chain(...).collect().
What is the most idiomatic way to combine two vectors in Rust?
If you want to add all elements from one vector into another, extend or append is usually the most idiomatic choice. The best one depends on whether you want to keep the second vector.
What is the difference between append and extend in Rust?
append takes &mut Vec<T> and empties the source vector. extend accepts any iterable and is more general.
Does append copy elements in Rust?
No. It moves the elements from the second vector into the first.
How do I concatenate vectors without losing the second vector?
For Copy types, use a.extend(&b). For non-Copy types, use a.extend(b.iter().cloned()).
Mini Project
Description
Create a small Rust program that combines task lists from two sources. This demonstrates how to merge vectors while choosing whether to move data or preserve the original values. It mirrors a common real-world problem: combining data from multiple modules or API responses.
Goal
Build a Rust program that merges two vectors of tasks and prints the final combined list.
Requirements
- Create one vector of existing tasks.
- Create a second vector of incoming tasks.
- Combine the two vectors into one final list.
- Print the merged result.
- Show at least one approach that keeps the second vector unchanged.
Keep learning
Related questions
Accessing Cargo Package Metadata in Rust
Learn how to read Cargo package metadata like version, name, and authors in Rust using compile-time environment macros.
Associated Types vs Generic Type Parameters in Rust: When to Use Each
Learn when to use associated types vs generic parameters in Rust traits, with clear rules, examples, and practical API design advice.
Convert an Integer to a String in Rust
Learn the current Rust way to convert integers to strings, why `to_str()` no longer works, and when to use `to_string()` or `format!`.