Benötigen Sie eine ganzheitliche Erklärung zu Rusts Zellen- und Referenzzählertypen

73

In der Rust-Standardbibliothek gibt es mehrere Wrapper-Typen:

Nach meinem Verständnis sind dies Wrapper, die weitere Möglichkeiten bieten als eine einfache Referenz. Obwohl ich einige Grundlagen verstehe, kann ich nicht das ganze Bild sehen.

Was machen sie genau? Bieten Zellen und Familien mit Referenzzählung orthogonale oder ähnliche Merkmale?

Boiethios
quelle
5
Bitte beschreiben Sie, was Sie nicht verstehen. In der Dokumentation, mit der Sie verlinkt haben, haben Hunderte (oder Tausende) Personen sie gelesen, und wahrscheinlich tragen zehn bis Hunderte von Personen dazu bei. Was können wir möglicherweise sagen, das sich von dem unterscheidet, was bereits gesagt wurde, insbesondere wenn Sie uns nicht sagen, was Sie nicht verstehen?
Shepmaster
1
@ Shepmaster Die Erklärungen in der Dokumentation sprechen von innerer Veränderbarkeit . Dieses Konzept ist für mich unklar. Vielleicht war meine Frage auch unklar.
Boiethios
3
Eine schnelle Suche im Internet ergab ein Kapitel im Buch über innere Veränderlichkeit , einen Blog-Beitrag und eine SO-Frage . Vielleicht können Sie jetzt, da Sie wissen, worüber Sie unklar sind, Nachforschungen anstellen und Ihre Frage aktualisieren.
Shepmaster

Antworten:

138

In Rust gibt es zwei wesentliche Konzepte:

  • Eigentum,
  • Wandlungsfähigkeit.

Die verschiedenen Zeigertypen ( Box, Rc, Arc) mit betroffenen Eigentümer : Sie ermöglichen die Steuerung , ob ein einzelner oder mehr Eigentümer für ein einzelnes Objekt sind.

Auf der anderen Seite sind die verschiedenen Zellen ( Cell, RefCell, Mutex, RwLock, AtomicXXX) mit betroffenen Mutability .


Die Grundregel für Rusts Sicherheit lautet Aliasing XOR Mutability . Das heißt, ein Objekt kann nur dann sicher mutiert werden, wenn kein herausragender Bezug zu seinem Inneren besteht.

Diese Regel wird im Allgemeinen beim Kompilieren vom Ausleihprüfer durchgesetzt :

  • Wenn Sie eine haben &T, können Sie nicht auch eine &mut Tfür dasselbe Objekt im Gültigkeitsbereich haben.
  • Wenn Sie eine haben &mut T, können Sie auch keinen Verweis auf dasselbe Objekt im Bereich haben.

Manchmal ist dies jedoch nicht flexibel genug. Manchmal benötigen (oder möchten) Sie die Möglichkeit, mehrere Verweise auf dasselbe Objekt zu haben und es dennoch zu mutieren. Geben Sie die Zellen ein .

Die Idee von Cellund RefCellist es, die Veränderbarkeit bei Aliasing auf kontrollierte Weise zu ermöglichen :

  • Cell verhindert die Bildung von Verweisen auf sein Inneres, vermeidet baumelnde Verweise,
  • RefCellverschiebt die Durchsetzung von Aliasing XOR Mutability von der Kompilierungszeit zur Laufzeit.

Diese Funktionalität wird manchmal als Bereitstellung innerer Veränderbarkeit beschrieben, dh , ein Objekt, das ansonsten von außen unveränderlich aussieht ( &T), kann tatsächlich mutiert werden.

Wenn diese Veränderlichkeit über mehrere Threads erstreckt, werden Sie stattdessen verwenden Mutex, RwLockoder AtomicXXX; Sie bieten die gleiche Funktionalität:

  • AtomicXXXsind nur Cell: kein Bezug zum Innenraum, nur Ein- / Ausziehen,
  • RwLockist nur RefCell: kann durch Wachen Hinweise auf das Innere erhalten ,
  • Mutexist eine vereinfachte Version, RwLockdie nicht zwischen einem Nur-Lese-Schutz und einem Schreibschutz unterscheidet; so konzeptionell ähnlich wie RefCellbei nur einer borrow_mutMethode.

Wenn Sie aus einem C ++ - Hintergrund stammen:

  • Boxist unique_ptr,
  • Arcist shared_ptr,
  • Rcist eine nicht threadsichere Version von shared_ptr.

Und die Zellen bieten eine ähnliche Funktionalität wie mutable, außer mit zusätzlichen Garantien, um Aliasing-Probleme zu vermeiden. Stellen Sie sich Cellals std::atomicund RefCellals nicht threadsichere Version von vor std::shared_mutex(die wirft, anstatt zu blockieren, wenn die Sperre aufgehoben wird).

Matthieu M.
quelle
2
Vielen Dank so viel, Sie antworten genau an alle meine Ratlosigkeit über „kompliziert“ Typen in Rust. Auch der Vergleich mit C ++ ist perfekt.
Boiethios
3
@ Boiethios: Ja, genau das ist es. Jeder Verweis / Zeiger ist "ein Alias" für die realen Daten (ein anderer Name für dieselbe "Person" ist schließlich ein Alias), und in der Software wird über Aliasing gesprochen, wenn mehrere Aliase gleichzeitig vorhanden sind Zeit.
Matthieu M.
3
Die erste Ausgabe des Buches enthielt ein Kapitel dazu . Es ist einer von denen , die in der Rewrite verloren war, was ich denke , ist bedauerlich - vielleicht sollte es in einem Anhang oder etwas gemacht werden
trentcl
6
Wenn Aliasing XOR-Mutabilität die Sicherheitsregel ist, bedeutet dies, dass (nicht Aliasing) UND (nicht Mutabilität) unsicher ist? Aber sicher, wenn es kein Aliasing UND keine Veränderlichkeit gibt, ist das absolut sicher? Ich denke, du willst dort etwas anderes als XOR.
Lii
11
Vielleicht sollte der Slogan NAND anstelle von XOR verwenden: P
Rufflewind
14

Dank der guten Antwort von Matthieu ist hier ein Diagramm, das den Menschen hilft, die Verpackung zu finden, die sie benötigen:

+-----------+
| 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>> |
                                           +================+
  1. In diesen Fällen Tkann durch ersetzt werdenBox<T>
  2. Verwenden Sie, AtomicTwenn Teine booloder eine Zahl ist

Um zu wissen, ob Sie Mutexoder verwenden sollten RwLock, lesen Sie diese verwandte Frage .

Boiethios
quelle