Когда vec! Создает разные элементы или нет?

Oct 21 2020

Я только что наткнулся на следующий код в 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} }]

ссылка на ржавую площадку

По-видимому, у v1него есть 2 разных HashMap, а у v2него только одна. Как это случилось? Не следует v2оценивать Arc::new(Mutex::new(HashMap::<i32, i32>::new()))дважды (например, v1do) и, таким образом, создавать два разных элемента? Это где-то «ленивая» оценка?

Простите мой вопрос новичку по ржавчине, заранее спасибо!

Ответы

9 kmdreko Oct 21 2020 at 14:06

vec![value; n]Синтаксис используется , Cloneчтобы дублировать значение и заполнить вектор. В документах даже упоминается такой сценарий:

Это будет использоваться cloneдля дублирования выражения, поэтому следует быть осторожным при использовании этого с типами, имеющими нестандартную Cloneреализацию. Например, vec![Rc::new(1); 5]будет создан вектор из пяти ссылок на одно и то же целочисленное значение в рамке, а не из пяти ссылок, указывающих на независимо упакованные целые числа.

3 PeterHall Oct 21 2020 at 14:03

В vec!макро - клоны ценность предоставленного выражения для заполнения вектора до требуемой длины.

An Arc- это умный указатель с подсчетом ссылок, который используется при клонировании. Каждый раз, когда вы клонируете объект Arc, он увеличивает счетчик ссылок на базовые данные, но базовые данные остаются прежними.

Вот что происходит в вашем примере. Элементы вектора - это разные указатели на одно и то же HashMap.