Rust pointers: Difference between revisions

From wikinotes
Line 106: Line 106:
== RefCell<T> ==
== RefCell<T> ==
<blockquote>
<blockquote>
This wraps an object with a single parent, but allows a mutable reference while immutable references exist.<br>
See https://doc.rust-lang.org/stable/book/ch15-05-interior-mutability.html


</blockquote><!-- RefCell<T> -->
</blockquote><!-- RefCell<T> -->

Revision as of 01:45, 10 February 2023

Documentation

custom smart pointers https://doc.rust-lang.org/stable/book/ch15-02-deref.html

Pointers/References

let foo = String::new("hi");
&foo   // `&` get reference to foo

let ref = &foo;
*ref   // `*` de-reference to get foo instance

Smart Pointers

The standard library implements some reusable smart-pointers to handle edge-cases.
Libraries may implment their own smart-pointers (and so can you).

Pointer Relevant Traits

  • Deref alters how the de-reference operator (*) behaves
  • DerefMut alters how the de-reference operator (*) behaves for mutable references
  • Drop alters the object's destructor, normally run when the object falls out of scope.

Box<T>

Box types let you represent recursive types, where the total size is unknown at compile time,
by replacing your type with a pointer to it.

The docs use the example of a recursive enum.
An Enum's size is determined by it's largest possible value.
If an enum refers to an instance of itself the compiler is unable to determine it's size.

The box type allocates your object to the heap, and returns a pointer to it.
Pointers have a known size, so you can assign that instead.
Also, it implements the Deref trait, which allows you to use box as if it were a reference to the object you assigned to it.

#[derive(Debug)]
enum Path {
    Dir(String, Box<Path>),
    File(String),
}

impl Path {
    fn file(file: &str) -> Box<Path> {
        Box::new(
            Path::File(file.to_string())
        )
    }

    fn dir(dir: &str, path: Box<Path>) -> Box<Path> {
        Box::new(
            Path::Dir(dir.to_string(), path)
        )
    }
}

fn main() {
    let mypath = Path::dir("/var", Path::dir("/tmp", Path::file("/foo.txt")));
    dbg!(mypath);
}

Rc<T>

The Rc (Reference Counting) smart-pointer lets you have an object with multiple owners.
This is useful for graphs, where a node may have multiple parents.

This behaves similarly to Box in that it returns a pointer with an overridden dereference operator, but it also ensures that as long as one reference still exists to an object, it won't get drop() called on it.

use std::rc::Rc;

#[derive(Debug)]
enum Node {
    Parents(Vec<Rc<Node>>),
    Root,
}

fn main() {
    let a = Rc::new(Node::Root);
    let b1 = Node::Parents(vec![
        Rc::clone(&a),
    ]);
    let b2 = Node::Parents(vec![
        Rc::clone(&a),
    ]);
    dbg!(&b1);
    dbg!(&b2);
}

RefCell<T>

This wraps an object with a single parent, but allows a mutable reference while immutable references exist.
See https://doc.rust-lang.org/stable/book/ch15-05-interior-mutability.html

Function Pointers