Quand «vec!» Crée-t-il différents éléments, ou pas?

Oct 21 2020

Je viens de tomber sur le code suivant dans 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} }]

lien vers le terrain de jeu de la rouille

Il a apparemment v12 HashMaps différents, alors qu'il v2n'en a qu'un seul. Comment est-ce arrivé? Ne devrait-il pas v2évaluer Arc::new(Mutex::new(HashMap::<i32, i32>::new()))deux fois (comme le v1font) et créer ainsi deux éléments différents? S'agit-il d'une sorte d'évaluation «paresseuse» quelque part?

Pardonnez ma question de débutant à la rouille, merci d'avance!

Réponses

9 kmdreko Oct 21 2020 at 14:06

La vec![value; n]syntaxe utilise Clonepour dupliquer la valeur et remplir le vecteur. La documentation mentionne même ce genre de scénario:

Cela utilisera clonepour dupliquer une expression, donc il faut être prudent en utilisant cela avec des types ayant une Cloneimplémentation non standard . Par exemple, vec![Rc::new(1); 5]créera un vecteur de cinq références à la même valeur entière encadrée, et non pas cinq références pointant vers des entiers encadrés indépendamment.

3 PeterHall Oct 21 2020 at 14:03

La vec!macro clone la valeur de l'expression fournie pour remplir le vecteur jusqu'à la longueur demandée.

An Arcest un pointeur intelligent compté par référence, qui est partagé par clonage. Chaque fois que vous clonez un Arc, cela augmente le nombre de références aux données sous-jacentes, mais les données sous-jacentes sont toujours les mêmes.

C'est donc ce qui se passe dans votre exemple. Les éléments du vecteur sont des pointeurs différents vers le même HashMap.