Direct naar de hoofdinhoud
Module 6 · Les 2 van 212/14 in de cursus~15 min
Modulelessen (2/2)

Slimme wijzers: Box en Rc

Een slimme pointer is een datastructuur die zich gedraagt ​​als een pointer, maar beschikt over metagegevens en extra mogelijkheden (zoals het tellen van referenties of automatisch geheugenbeheer).

In Rust lenen gewone referenties (zoals &) alleen gegevens. Slimme wijzers daarentegen zijn vaak eigenaar van de gegevens waarnaar ze verwijzen. Veel voorkomende voorbeelden zijn String en Vec<T>, maar de standaardbibliotheek biedt andere gespecialiseerde bibliotheek.


Box<T> voor heaptoewijzing

De eenvoudigste slimme aanwijzer is Box<T>, waarmee gegevens op de heap worden opgeslagen in plaats van op de stapel. Alleen de pointer naar de aan de heap toegewezen gegevens blijft op de stapel staan.

Het wordt voornamelijk gebruikt in de volgende gevallen:

  1. Wanneer u een type heeft waarvan de grootte niet bekend is tijdens het compileren (zoals een recursief type), en u een waarde van dat type wilt gebruiken in een context die een exacte grootte vereist.
  2. Wanneer u het eigendom van een grote hoeveelheid gegevens wilt overdragen zonder deze te kopiëren.

Basisvoorbeeld:

Rust
fn main() {
    let b = Box::new(5); // allocates the value 5 on the heap
    println!("b = {}", *b); // dereferences with * to read the value
}

Recursieve typen en nadelenlijsten

Een recursief type is een type dat een waarde van zichzelf kan bevatten als onderdeel van de definitie ervan. Rust moet tijdens het compileren de exacte grootte van een type weten. Omdat de diepte van een recursief type oneindig kan zijn, genereert de compiler een fout, tenzij je een Box gebruikt (die een vaste grootte heeft, omdat het een pointer is):

Rust
enum List {
    Cons(i32, Box<List>),
    Nil,
}

Rc<T>: Referentietelling

Er zijn gevallen waarin een enkele waarde meerdere eigenaren kan hebben. De slimme aanwijzer Rc<T> (Reference Counted) houdt het aantal verwijzingen naar een waarde bij om te bepalen of de waarde nog in gebruik is. Als het aantal naar nul daalt, wordt de toewijzing van de bron veilig opgeheven.

[!NOTE] Rc<T> is alleen geschikt voor scenario's met één thread. Voor scenario's met meerdere threads (gelijktijdig) moet u Arc<T> gebruiken (Atomic Reference Counted).

Rust
use std::rc::Rc;

fn main() {
    let a = Rc::new(5);
    let b = Rc::clone(&a); // increments the reference count to 2
    println!("References: {}", Rc::strong_count(&a));
}

Probeer het zelf

Oefening 1: Heaptoewijzing met Box

Oefening#rust.m6.l2.e1
Pogingen: 0Laden…

Wijs een geheel getal van 42 toe aan de heap met behulp van Box::new en wijs deze toe aan een variabele met de naam val. Druk vervolgens de waarde af die is opgeslagen in de Box door deze expliciet te derefereren met de operator *.

Editor laden…
Toon hint

Gebruik `let val = Box::new(42);` om de waarde op te slaan in heap en verwijder de referentie met `*val` binnen `println!`.

Oplossing beschikbaar na 3 pogingen

Oefening 2: Recursieve gegevensstructuur (lijst met nadelen)

Oefening#rust.m6.l2.e2
Pogingen: 0Laden…

Definieer een recursieve opsomming met de naam Lijst die twee varianten bevat: Cons die een tupel omsluit (i32, Box<Lijst>) en Nil die het einde van de lijst vertegenwoordigt. Maak in de hoofdfunctie een gekoppelde lijst met het element 1 gevolgd door Nil.

Editor laden…
Toon hint

De enum wordt gedeclareerd als `enum List { Cons(i32, Box<List>), Nil }`. Instantieer de lijst met `List::Cons(1, Box::new(List::Nil))`.

Oplossing beschikbaar na 3 pogingen

Oefening 3: Eigendom delen met Rc

Oefening#rust.m6.l2.e3
Pogingen: 0Laden…

Gebruik std::rc::Rc om een ​​gedeeld geheel getal te maken dat de waarde 100 in een variabele a bevat. Kloon de verwijzing naar een variabele b met behulp van Rc::clone. Druk ten slotte het aantal actieve referenties af met behulp van de functie Rc::strong_count.

Editor laden…
Toon hint

Creëer de waarde met `Rc::new(100)`. Kloon met `Rc::clone(&a)`en geef het aantal eigenaren weer met`Rc::strong_count(&a)`.

Oplossing beschikbaar na 3 pogingen