Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Vector of Vectors created with the vec! macro contain different capacities

Tags:

vector

rust

I have a vectormatrix_a, which contains 3 vectors, and it is initialized with the vec! macro.

Every vector should have a capacity of 3, due to Vec::with_capacity(dim), but only the last vector has a capacity of 3. The other vectors have a capacity of 0.

Can someone explain why that is?

fn main() {
    let dim = 3;
    let matrix_a: Vec<Vec<i32>> = vec![Vec::with_capacity(dim); dim];

    for vector in matrix_a{
        println!("Capacity of vector: {}", vector.capacity());
    }
}

Output:

Capacity of vector: 0
Capacity of vector: 0
Capacity of vector: 3
like image 525
Dominique M. Avatar asked Aug 25 '15 11:08

Dominique M.


People also ask

What is a VEC in Rust?

Vector is a module in Rust that provides the container space to store values. It is a contiguous resizable array type, with heap-allocated contents. It is denoted by Vec<T>. Vectors in Rust have O(1) indexing and push and pop operations in vector also take O(1) complexity.

How do you initialize VEC in Rust?

In Rust, there are several ways to initialize a vector. In order to initialize a vector via the new() method call, we use the double colon operator: let mut vec = Vec::new();

How do you clear a vector in Rust?

To remove all elements from a vector in Rust, use . retain() method to keep all elements the do not match. let mut v = vec![

How do you tell if a vector is empty in Rust?

vector::empty() The empty() function is used to check if the vector container is empty or not.


1 Answers

According to the documentation, vec! is defined as:

macro_rules! vec {
    ( $ elem : expr ; $ n : expr ) => (
        $ crate:: vec:: from_elem ( $ elem , $ n )
    );
    ( $ ( $ x : expr ) , * ) => (
        < [ _ ] > :: into_vec (
            $ crate:: boxed:: Box:: new ( [ $ ( $ x ) , * ] )
        )
    );
    ( $ ( $ x : expr , ) * ) => ( vec ! [ $ ( $ x ) , * ] )
}

In your case, it means that:

vec![Vec::with_capacity(dim); dim]

is expanded into:

std::vec::from_elem(Vec::with_capacity(dim), dim)

The definition of Vec::from_elem is hidden in the documentation, but can be found in the source:

pub fn from_elem<T: Clone>(elem: T, n: usize) -> Vec<T> {
    unsafe {
        let mut v = Vec::with_capacity(n);
        let mut ptr = v.as_mut_ptr();

        // Write all elements except the last one
        for i in 1..n {
            ptr::write(ptr, Clone::clone(&elem));
            ptr = ptr.offset(1);
            v.set_len(i); // Increment the length in every step in case Clone::clone() panics
        }

        if n > 0 {
            // We can write the last element directly without cloning needlessly
            ptr::write(ptr, elem);
            v.set_len(n);
        }

        v
    }
}

And this where the heart of the mystery is solved:

  • the element is cloned n - 1 times, for the n - 1 first elements of the vector, and then moved into the n-th slot.
  • cloning a vector does not clone its capacity, only its elements.

Thus the result you get is exactly as intended, if not as expected.

like image 96
Matthieu M. Avatar answered Nov 13 '22 17:11

Matthieu M.