bayinamy
bayinamy

Reputation: 497

When does `vec!` create different elements, or not?

I just came across the following code in Rust:

use std::collections::HashMap;
use std::sync::{Arc, Mutex};

fn main() {
    let mut v1 = vec![HashMap::<i32, i32>::new(); 2];
    v1[0].insert(0,0);
    v1[1].insert(1,1);
    println!("{:?}", v1);
    
    let v2 = vec![Arc::new(Mutex::new(HashMap::<i32, i32>::new())); 2];
    v2[0].lock().unwrap().insert(0,0);
    v2[1].lock().unwrap().insert(1,1);
    println!("{:?}", v2);
}

// outputs:
// [{0: 0}, {1: 1}]
// [Mutex { data: {0: 0, 1: 1} }, Mutex { data: {0: 0, 1: 1} }]

link to rust playground

It's apparently v1 has 2 different HashMaps, while v2 has only one. How's that happened? Shouldn't v2 evaluates Arc::new(Mutex::new(HashMap::<i32, i32>::new())) twice (like v1 do) and thus create two different elements? Is it some kind of "lazy" evaluation somewhere?

Pardon my rust newbie question, thanks in advance!

Upvotes: 4

Views: 209

Answers (2)

kmdreko
kmdreko

Reputation: 60132

The vec![value; n] syntax uses Clone to duplicate the value and fill up the vector. The docs even mention this kind of scenario:

This will use clone to duplicate an expression, so one should be careful using this with types having a nonstandard Clone implementation. For example, vec![Rc::new(1); 5] will create a vector of five references to the same boxed integer value, not five references pointing to independently boxed integers.

Upvotes: 9

Peter Hall
Peter Hall

Reputation: 58735

The vec! macro clones value of the provided expression to fill the vector up to the requested length.

An Arc is a reference-counted smart pointer, which is shared by cloning. Each time you clone an Arc, it increases the reference count to the underlying data, but the underlying data is still the same.

So that's what is happening in your example. The elements of the vector are different pointers to the same HashMap.

Upvotes: 3

Related Questions