Il existe plusieurs types de wrapper dans la bibliothèque standard Rust:
std::cell
module : Cell
et RefCell
Rc
et Arc
.std::sync
module : Mutex
ou AtomicBool
par exempleSi je comprends bien, ce sont des enveloppes qui offrent des possibilités supplémentaires par rapport à une simple référence. Bien que je comprenne quelques notions de base, je ne peux pas voir l’ensemble du tableau.
Que font-ils exactement? Les cellules et les familles dénombrées par référence fournissent-elles des caractéristiques orthogonales ou similaires?
Il y a deux concepts essentiels dans Rust:
Les différents types de pointeurs (Box
, Rc
, Arc
) concernent la propriété : ils permet de contrôler s'il y a un ou plusieurs propriétaires pour un seul objet.
Par contre, les différentes cellules (Cell
, RefCell
, Mutex
, RwLock
, AtomicXXX
) sont concernées Mutabilité .
La règle fondatrice de la sécurité de Rust est aliasing XOR mutabilité. Autrement dit, un objet ne peut être muté en toute sécurité que s'il n'existe aucune référence en suspens à son intérieur.
Cette règle est généralement appliquée à la compilation par le vérificateur d'emprunt :
&T
, vous ne pouvez pas aussi avoir un &mut T
vers le même objet dans la portée,&mut T
, vous ne pouvez pas non plus avoir de référence au même objet dans la portée.Cependant, parfois, ce n'est pas assez flexible. Parfois, vous DEVEZ (ou souhaitez) avoir la possibilité d’avoir plusieurs références au même objet tout en les transformant. Entrez le cellules.
L'idée de Cell
et RefCell
est de permettre la mutabilité en présence de repliement du spectre de manière contrôlée :
Cell
empêche la formation de références à son intérieur, en évitant les références en suspens,RefCell
déplace l'application de aliasing XOR mutabilité = de la compilation à l'exécution].Cette fonctionnalité est parfois décrite comme fournissant mutabilité intérieure, c’est-à-dire un objet qui semble immuable de l’extérieur (&T
) peut effectivement être muté.
Lorsque cette mutabilité s'étend sur plusieurs threads, vous utiliserez plutôt Mutex
, RwLock
ou AtomicXXX
; ils offrent les mêmes fonctionnalités:
AtomicXXX
ne sont que Cell
: pas de référence à l'intérieur, mais juste pour entrer/sortir,RwLock
n'est que RefCell
: on peut obtenir des références à l'intérieur par des gardes ,Mutex
est une version simplifiée de RwLock
qui ne fait pas la distinction entre un protecteur en lecture seule et un protecteur en écriture; conceptuellement semblable à un RefCell
avec seulement un borrow_mut
méthode.Si vous venez d'un contexte C++:
Box
est unique_ptr
,Arc
est shared_ptr
,Rc
est une version non sécurisée pour les threads de shared_ptr
.Et les cellules offrent une fonctionnalité similaire à mutable
, à l'exception des garanties supplémentaires permettant d'éviter les problèmes d'aliasing; penser à Cell
comme std::atomic
et RefCell
comme une version non thread-safe de std::shared_mutex
(qui jette au lieu de bloquer si le verrou est pris).
Grâce à bonne réponse de Matthie , voici un diagramme pour aider les gens à trouver l'emballage qui leur convient:
+-----------+
| Ownership |
+--+--------+ +================+
| +-Static----->| T |(1)
| | +================+
| |
| | +================+
| +-----------+ | Local Val| Cell<T> |(1)
+-Unique-->| Borrowing +--+-Dynamic---->|----------------|
| +-----------+ | Ref| RefCell<T> |(1)
| | +================+
| |
| | +================+
| | Threaded | AtomicT |(2)
| +-Dynamic---->|----------------|
| | Mutex<T> |(1)
| | RwLock<T> |(1)
| +================+
|
|
| +================+
| +-No--------->| Rc<T> |
| | +================+
| Locally +-----------+ |
+-Shared-->| Mutable? +--+ +================+
| +-----------+ | Val| Rc<Cell<T>> |
| +-Yes-------->|----------------|
| Ref| Rc<RefCell<T>> |
| +================+
|
|
| +================+
| +-No--------->| Arc<T> |
| | +================+
| Shared +-----------+ |
+-Between->| Mutable? +--+ +================+
Threads +-----------+ | | Arc<AtomicT> |(2)
+-Yes-------->|----------------|
| Arc<Mutex<T>> |
| Arc<RwLock<T>> |
+================+
T
peut être remplacé par Box<T>
AtomicT
lorsque T
est un bool
ou un nombrePour savoir si vous devez utiliser Mutex
ou RwLock
, voir cette question connexe .