Ben Chuanlong Du's Blog

It is never too late to learn.

Pointer, Reference and Ownership in Rust

Things on this page are fragmentary and immature notes/thoughts of the author. Please read with your own judgement!

Tips and Traps

References & Pointers

  1. You should avoid using lifetime annotation as much as possible especially in public APIs. Leveraging smart pointers is a good approach to elide lifetime annotations. For more discussions on this, please refer to Smart pointers: The secret to write clean Rust code .

Struct std::marker::PhantomData is a zero-sized type used to mark things that "act like" they own a T.

Module std::boxed is a (fat) pointer type for heap allocation. Box<T>, casually referred to as a box, provides the simplest form of heap allocation in Rust. Boxes provide ownership for this allocation, and drop their contents when they go out of scope. Boxes also ensure that they never allocate more than isize::MAX bytes.

Module std::cell is a module providing shareable mutable containers.

Module std::rc is a module providing single-threaded reference-counting pointers. Rc stands for Reference Counted. The type Rc<T> provides shared ownership of a value of type T, allocated in the heap. Invoking clone on Rc produces a new pointer to the same allocation in the heap. When the last Rc pointer to a given allocation is destroyed, the value stored in that allocation (often referred to as "inner value") is also dropped. Shared references in Rust disallow mutation by default, and Rc is no exception: you cannot generally obtain a mutable reference to something inside an Rc. If you need mutability, put a Cell or RefCell inside the Rc.

Struct std::sync::Arc A thread-safe reference-counting pointer. Arc stands for Atomically Reference Counted. The type Arc provides shared ownership of a value of type T, allocated in the heap. Invoking clone on Arc produces a new Arc instance, which points to the same allocation on the heap as the source Arc, while increasing a reference count. When the last Arc pointer to a given allocation is destroyed, the value stored in that allocation (often referred to as cinner value) is also dropped.

Shared references in Rust disallow mutation by default, and Arc is no exception: you cannot generally obtain a mutable reference to something inside an Arc. If you need to mutate through an Arc, use Mutex, RwLock, or one of the Atomic types.

Ownership

  • Each value in Rust has a variable that's called its owner.
  • There can only be one owner at a time.
  • When the owner goes out of scope, the value will be dropped.
In [5]:
{
    let s1 = String::from("how are you");
    let s2 = s1;
    println!("{}", s1);
}
    let s2 = s1;
        ^^ 
unused variable: `s2`
help: if this is intentional, prefix it with an underscore

_s2
    let s2 = s1;
             ^^ value moved here
    println!("{}", s1);
                   ^^ value borrowed here after move
    let s1 = String::from("how are you");
        ^^ move occurs because `s1` has type `String`, which does not implement the `Copy` trait
borrow of moved value: `s1`

Borrow

  • Allow infinite borrows for read-only access
  • Read-only borrows make the original data immutable
  • Only allowed to pass one borrow at a time for write access
In [4]:
{
    let mut s1 = String::from("how are you");
    let s2 = &s1;
    s1.push('?');
    println!("{}", s2);
}
    s1.push('?');
    ^^^^^^^^^^^^ mutable borrow occurs here
    let s2 = &s1;
             ^^^ immutable borrow occurs here
    println!("{}", s2);
                   ^^ immutable borrow later used here
cannot borrow `s1` as mutable because it is also borrowed as immutable
In [11]:
{
    let mut s = String::from("how are you");
    println!("{}", &*s);
}
how are you
Out[11]:
()

Partial Borrowing

Rc + RefCell is another alternative but it is the least recommended as it pushes compile time borrow checking to runtime and might cause runtime panics. For more discussions, please refer to Cell and Refcell in Rust .

In [ ]:
 

Comments