27Mar

Engineering Notebook: More Rust Basics

Posted by Elf Sternberg as Uncategorized

Continuing on with my engineering notebook, here’s what I’ve been learning about Rust recently. Mostly still following Beingessner’s book, which is about memory management primitives in Rust.

The first thing, as I covered last time is that the book teaches Rust’s peculiar (but excellent) flavor of memory management. Along the way, it teaches Rust’s sum types (using enum as its keyword), matching with completion, and Rust’s maybe types (using Option<>).

One thing it doesn’t teach is about is tuple structs. I had to look them up; I keep encountering them in other people’s code, but they weren’t obvious to me and I couldn’t remember seeing them in The Rust Programming Language, so I kept calling them "tuple types," but no, they’re called tuple structs, and you access their internals via a dotted index:

struct Color(i32, i32, i32); // Red, Green, Blue
let lightskyblue = Color(135, 206, 250);
let amount_of_blue = lightskyblue.2;

Box<T>: The thing with Rust is that you still have to care, a lot, about whether something is on the stack or the heap. Using the Box<T> type automatically puts something on the heap, and is tracked in such a way that Rust deletes it automatically when the handle to it goes out of scope.

Rc<T> is a wrapper around Box that allows for multiple handles to point to T, counting the number of handles referring to T, and automatically deleting T when the count goes to zero.

Arc<T> is just like Rc<T> except that it also wraps the counter in a mutex handler and allows for multiple threads to reference the object safely.

RefCell<T> allows one to borrow a referenced object from inside an Rc or Arc or other immutable container. This allows the user to mutate the contents of what would other be an immutable. When using RefCell<T>, you must use .borrow() or .borrow_mut() to "dynamically borrow" and object that normally would not be borrow-able.

Rust continues to be… weird. This one in particular gets me:

pub struct List<T> { head: Link<T>, }
type Link<T> = Option<Rc<Node<T>>>;
struct Node<T> { elem: T, next: Link<T>, }
pub struct Iter<'a, T:'a> { next: Option<&'a Node<T>>, }

// In body of impl<T> List<T>:
pub fn iter(&self) -> Iter<T> {
        Iter { next: self.head.as_ref().map(|node| &**node) }
}

I mean, I get that Rc is a pointer, and as_ref turns the head object into a reference to the head object, and map only works if node is not None, so we have to dereference it twice, and then to make Rustc happy that we’re saving a reference mark it as a reference to this twice-dereferenced thing, but… oy. That just looks ugly.

And yes, I get that I have to internalize all this before I can even begin to write Rust meaningfully.

Comment Form

Subscribe to Feed

Categories

Calendar

March 2018
M T W T F S S
« Feb   Apr »
 1234
567891011
12131415161718
19202122232425
262728293031