macro_rules! vec_no_clone {
{$v: expr; $c: expr} => { ... };
{$($v: expr),* $(,)?} => { ... };
}std only.Expand description
Version of the vec! macro where the value does not have to implement Clone.
Useful for unclonable types or where Clone is exerting undesired behaviour.
§Uncloneable Types
When using vec![x; count], the type of x has to implement Clone, because
x is cloned count - 1 times into all the vector elements except the first one.
For example, calling vec! will result in a panic during compile time here,
because UnclonableWrapper is not cloneable:
struct UnclonableWrapper(u8);
let x = vec![UnclonableWrapper(0); 5];The vec_no_clone! macro takes a different approach.
Instead of cloning UnclonableWrapper(0), it treats it as an
expression which is
called 5 times in this case.
So 5 independent UnclonableWrapper objects, each with its own location in
memory, are created:
use map_macro::vec_no_clone;
struct UnclonableWrapper(u8);
let x = vec_no_clone![UnclonableWrapper(0); 5];
assert_eq!(x.len(), 5);A real-world example where vec_no_clone! is a useful drop-in replacement
for vec! are atomic types, which are not clonable:
use std::sync::atomic::AtomicU8;
use map_macro::vec_no_clone;
let x = vec_no_clone![AtomicU8::new(0); 5];
assert_eq!(x.len(), 5);§Types where Clone exerts the wrong Behaviour
vec_no_clone! is not only useful for unclonable types, but also for types
where cloning them is not what you want.
The best example would be a reference counted pointer Rc.
When you clone an Rc, a new instance referencing the same location in memory
is created.
If you’d rather have multiple independent reference counted pointers to
different memory locations, you can use vec_no_clone! as well:
use map_macro::vec_no_clone;
use std::cell::RefCell;
use std::rc::Rc;
// simply clones the reference counted pointer for each element that
// is not the first
let shared_vec = vec![Rc::new(RefCell::new(0)); 2];
{
let mut first = shared_vec[0].borrow_mut();
*first += 1;
}
assert_eq!(*shared_vec[0].borrow(), 1);
// the second element is a clone of the reference counted pointer at
// the first element of the vector, referencing the same address in
// memory, therefore being mutated as well
assert_eq!(*shared_vec[1].borrow(), 1);
// the `vec_no_clone!` macro does not clone the object created by the
// first expression but instead calls the expression for each element
// in the vector, creating two independent objects, each with their
// own address in memory
let unshared_vec = vec_no_clone![Rc::new(RefCell::new(0)); 2];
{
let mut first = unshared_vec[0].borrow_mut();
*first += 1;
}
assert_eq!(*unshared_vec[0].borrow(), 1);
// the second element is not the same cloned reference counted
// pointer as it would be if it were constructed with the `vec!` macro
// from the standard library like it was above, therefore it is not
// mutated
assert_eq!(*unshared_vec[1].borrow(), 0);§Drawbacks of using Expressions
Since vec_no_clone! treats the value as an expression, you must provide the
initialization as input directly.
This, for example, won’t work:
use map_macro::vec_no_clone;
struct UnclonableWrapper(u8);
let a = UnclonableWrapper(0);
// a will have moved into the first element of x, raising a compile
// time error for the second element.
let x = vec_no_clone![a; 5];§Processing Lists of Elements
You can also use the macro with a list of elements, like vec!.
In fact, vec_no_clone! falls back to vec! in this case:
use map_macro::vec_no_clone;
let v1 = vec_no_clone![0, 1, 2, 3];
let v2 = vec![0, 1, 2, 3];
assert_eq!(v1, v2);
let v1: Vec<u8> = vec_no_clone![];
let v2: Vec<u8> = vec![];
assert_eq!(v1, v2);