R
RUSTY YELLOW PAGES

A Rust reference
for people writing Rust.

Part dictionary, part wiki — meant to be kept open in a second tab while you code.

Built for the moment you’re mid-code
  • what ? desugars to
  • whether Rc is thread-safe
  • how a match guard behaves

You want the answer, a snippet that compiles, and a short note on why — not a chapter.

Where the content comes from

Every page is distilled from the official Rust documentation — the Book, the Reference, the Nomicon, the API guidelines, std docs — and the mainstream Rust books. It is curated, not invented. If something is wrong, outdated or misleading, that is exactly the kind of feedback worth sending.

What a page looks like

Live excerpt · Concepts → Design Patterns & Idioms

A concept page doesn’t stop at an explanation. Best practices & deeper information breaks the topic into concrete scenarios — “creating a new object”, “working with collections” — each with a recommended way to handle it, the code, and the reasoning.

And nearly every concept page is written twice: once in the Classic Rust below, and again for no_std and bare-metal work, with its own explanation, its own examples and its own scenarios. Switch to it by pressing the Embedded button.

1 the scenario 2 the key line, marked // <- 3 why this way, not another
Concepts/Design Patterns & Idioms/mem::take / mem::replace
Scenario

Modifying an existing object

A batch processor needs to drain its pending items and hand them to a worker while leaving self in a valid, empty state — mem::take moves the Vec out without cloning it and without ever leaving the field uninitialized.

use std::mem;

struct BatchQueue {
    pending: Vec<String>,
}

impl BatchQueue {
    fn push(&mut self, item: String) {
        self.pending.push(item);
    }

    fn drain(&mut self) -> Vec<String> {
        mem::take(&mut self.pending) // <- moves `pending` out, replaces it with Vec::default() (empty)
    }
}

let mut queue = BatchQueue { pending: Vec::new() };
queue.push("order-1".to_string());
queue.push("order-2".to_string());

let batch = queue.drain(); // owns the items; queue.pending is now empty, not uninitialized
println!("{batch:?}");

Why this way: mem::take moves the Vec out in one step instead of cloning it just to satisfy the "every field must hold a value" rule, which the Rust Design Patterns book documents as the idiomatic way to change or extract a value behind &mut self without an unnecessary allocation.

Excerpt from a real page — nothing here is a mock-up. Open the full page →

Approaches

Community-contributed · live on the site today

There is rarely one right way to do something in Rust. Every scenario starts with the site’s recommended Classic solution; anyone can add an alternative implementation of the exact same scenario, attributed to them. Switch below — the code, the explanation and the byline all change together.

Scenario

Interior mutability

Approach:

Swapping the string held inside a RefCell for a new one, while getting the old string back to log it, needs to move the old value out of a borrowed &mut String — exactly what mem::replace is for.

use std::cell::RefCell;
use std::mem;

struct Session {
    last_message: RefCell<String>,
}

impl Session {
    fn set_message(&self, new_message: String) -> String {
        let mut slot = self.last_message.borrow_mut(); // <- RefMut<String>, derefs to &mut String
        mem::replace(&mut *slot, new_message) // <- swaps in `new_message`, returns the old one by value
    }
}

let session = Session { last_message: RefCell::new("connected".to_string()) };
let previous = session.set_message("processing".to_string());
println!("{previous}"); // "connected"

Why this way: RefCell::borrow_mut only ever gives out a &mut T, never ownership of the T itself, so mem::replace is the standard way to pull an owned value out of interior-mutable storage while leaving a valid replacement behind, per the std docs for mem::replace.

RefCell already packages this exact swap as a method. replace takes the mutable borrow and performs the mem::replace in one call, returning the old value, so the intermediate RefMut binding and the &mut *slot reborrow both disappear.

use std::cell::RefCell;

struct Session {
    last_message: RefCell<String>,
}

impl Session {
    fn set_message(&self, new_message: String) -> String {
        self.last_message.replace(new_message) // <- borrows and swaps in one step, returns the old String
    }
}

let session = Session { last_message: RefCell::new("connected".to_string()) };
let previous = session.set_message("processing".to_string());
println!("{previous}"); // "connected"

Why this way: there is no reborrow to get wrong, and the borrow is held for exactly the length of the swap rather than for as long as the binding stays in scope — which is what turns a later borrow() in the same function into a panic. The limitation is reach: replace exists on RefCell and Cell, so the moment the value lives behind a plain &mut — a struct field, a slice element, a MutexGuardmem::replace is the tool again. It also panics on an outstanding borrow with no way to recover; try_borrow_mut plus mem::replace is the version that lets you handle that case instead of aborting.

Browse

306 pages · 23 groups · press / to search

Syntax

180 pages · a dictionary, one page per token

Concepts

126 pages · a wiki with scenarios and approaches

How to help

The aim is for this reference to grow with contributions from people writing Rust, not just the maintainer. Contributions of all kinds are welcome — pointing out wrong information, reporting bugs, flagging what is missing, adding an article, covering a crate, or just taking part in the conversations. Enjoy your coding!

  • ApproachThe smallest useful PR. An additive markdown block on a scenario you know a better way through. You never touch anyone else’s content.
  • ArticleA technical, code-first piece under pages/articles/, with your byline on it.
  • Crate pageOne crate, the three fixed sections, one entry per API item.
  • CorrectionHighest priority of all. A reference is only worth trusting if it gets corrected.
  • ConversationNo PR needed — post on GitHub Discussions and it appears at the next rebuild.