vec![Mutex::new(0); 10] — won’t compile. Mutex isn’t Clone. iter::repeat_with(|| Mutex::new(0)).take(10).collect() builds ten fresh ones instead.
The vec![x; n] trap
The vec![x; n] macro is the obvious way to build a Vec of n copies. It works by cloning x n times:
1
2
| let zeros: Vec<u32> = vec![0; 5];
assert_eq!(zeros, vec![0, 0, 0, 0, 0]);
|
That’s fine for u32. It falls apart the moment you want something that isn’t Clone, or something where cloning gives you the wrong behavior — a counter, a channel endpoint, an Arc<Mutex<...>> you wanted to be separate locks:
1
2
3
| use std::sync::Mutex;
// error[E0277]: the trait `Clone` is not implemented for `Mutex<u32>`
// let locks = vec![Mutex::new(0); 10];
|
The fix: iter::repeat_with
iter::repeat_with(f) takes a closure and yields f() every time the iterator is polled. Combine with take(n).collect() and you’ve got a builder that calls the closure exactly n times — no Clone required:
1
2
3
4
5
| use std::iter;
use std::sync::Mutex;
let locks: Vec<Mutex<u32>> = iter::repeat_with(|| Mutex::new(0)).take(10).collect();
assert_eq!(locks.len(), 10);
|
Each Mutex is freshly constructed. They’re independent locks, not ten handles to the same one.
Stateful closures work too
Because the closure is FnMut, it can capture and mutate state — handy for counters, RNG-like generators, or anything where each element depends on the previous call:
1
2
3
4
5
| use std::iter;
let mut n = 0;
let counts: Vec<u32> = iter::repeat_with(|| { n += 1; n }).take(5).collect();
assert_eq!(counts, vec![1, 2, 3, 4, 5]);
|
Try that with vec![...; 5] and you’d get five copies of the same number.
When the closure is just a constructor call, you can pass the function directly — no || needed:
1
2
3
4
5
| use std::iter;
let buffers: Vec<Vec<i32>> = iter::repeat_with(Vec::new).take(3).collect();
assert_eq!(buffers.len(), 3);
assert!(buffers.iter().all(|b| b.is_empty()));
|
Vec::new here is a zero-argument function pointer, exactly what repeat_with wants.
When to reach for it
Any time you’d write a for loop to push n fresh items into a Vec, or any time vec![x; n] rejects you because the element isn’t Clone. It’s also the idiomatic way to seed parallel structures: repeat_with(|| Arc::new(Mutex::new(...))).take(workers).collect() gives each worker its own lock.
Available since Rust 1.28, lives in core::iter, no allocation overhead beyond the Vec itself.