Ownership

#106 Apr 2026

106. Iterator::by_ref — Take Part of an Iterator and Keep the Rest

Called iter.take(n).collect() and watched the borrow checker swallow the whole iterator? by_ref lets you consume a chunk and keep iterating from where you stopped.

The trap: adapters consume their iterator

Most iterator adapters take self, not &mut self. The moment you write iter.take(2), you have moved iter into the new Take adapter. The original binding is gone:

1
2
3
4
5
6
let v = vec![1, 2, 3, 4, 5];
let mut iter = v.into_iter();

let _first_two: Vec<i32> = iter.take(2).collect();
// let rest: Vec<i32> = iter.collect();
// ^^ error: use of moved value: `iter`

So even though there are clearly elements left, the variable that points at them is no longer usable.

The fix: iter.by_ref()

Iterator::by_ref returns a &mut Self — and &mut I itself implements Iterator whenever I: Iterator. Adapters chained off by_ref() consume from the underlying iterator without moving it:

1
2
3
4
5
6
7
8
let v = vec![1, 2, 3, 4, 5];
let mut iter = v.into_iter();

let first_two: Vec<i32> = iter.by_ref().take(2).collect();
let rest: Vec<i32> = iter.collect();

assert_eq!(first_two, [1, 2]);
assert_eq!(rest, [3, 4, 5]);

Same iterator, two phases, no clones, no indexing.

A real use: parse a header, then a body

The pattern shines when the front of a stream uses different rules than the rest. Pull lines until you hit a blank one, then hand the same iterator to the body parser:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
let input = "Subject: hi\nFrom: a@b\n\nbody line 1\nbody line 2";
let mut lines = input.lines();

let headers: Vec<&str> = lines
    .by_ref()
    .take_while(|l| !l.is_empty())
    .collect();

let body: Vec<&str> = lines.collect();

assert_eq!(headers, ["Subject: hi", "From: a@b"]);
assert_eq!(body, ["body line 1", "body line 2"]);

Without by_ref, take_while would have consumed lines whole and the body would be unreachable.

Gotcha: take_while peeks one past

take_while reads the first non-matching element to know when to stop — and that element is gone from the underlying iterator. With by_ref you’ll see this directly:

1
2
3
4
5
6
7
let mut nums = (1..).into_iter();

let small: Vec<i32> = nums.by_ref().take_while(|&n| n < 3).collect();
let next = nums.next();

assert_eq!(small, [1, 2]);
assert_eq!(next, Some(4)); // 3 was eaten by take_while

If you need to keep the boundary element, reach for Peekable instead.

When to use it

Any time you want to apply an adapter to part of an iterator and continue afterwards: chunked parsing, header/body splits, “take the first N then process the rest”, consuming until a sentinel. by_ref() turns “I moved my iterator and now I can’t use it” into a single extra method call.

99. std::mem::replace — Swap a Value and Keep the Old One

mem::take is great until your type doesn’t have a sensible Default. That’s where mem::replace steps in — you pick what gets left behind, and you still get the old value out of a &mut.

The shape of the problem

You can’t move a value out of a &mut T. The borrow checker rightly refuses. mem::take fixes this by swapping in T::default(), but an enum with no obvious default, or a type that deliberately doesn’t implement Default, leaves you stuck.

mem::replace(dest, src) is the escape hatch: it writes src into *dest and hands you back the old value.

1
2
3
4
5
6
7
use std::mem;

let mut greeting = String::from("Hello");
let old = mem::replace(&mut greeting, String::from("Howdy"));

assert_eq!(old, "Hello");
assert_eq!(greeting, "Howdy");

No clones, no unsafe, no Default required.

State machines without a default variant

This is where replace earns its keep. Picture a connection type where none of the variants makes a natural default — Disconnected is fine here, but it might be Error(e) somewhere else, and #[derive(Default)] would be a lie:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
use std::mem;

enum Connection {
    Disconnected,
    Connecting(u32),
    Connected { session: String },
}

fn finalize(conn: &mut Connection) -> Option<String> {
    match mem::replace(conn, Connection::Disconnected) {
        Connection::Connected { session } => Some(session),
        _ => None,
    }
}

let mut c = Connection::Connected { session: String::from("abc123") };
let session = finalize(&mut c);

assert_eq!(session.as_deref(), Some("abc123"));
assert!(matches!(c, Connection::Disconnected));

You get the owned String out of the Connected variant — no cloning the session, no Option<Connection> gymnastics, no unsafe.

Flushing a buffer with a fresh one

mem::take would leave behind an empty Vec with zero capacity. mem::replace lets you pre-size the replacement, which matters if you’re about to refill it:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
use std::mem;

struct Batch {
    items: Vec<u32>,
}

impl Batch {
    fn flush(&mut self) -> Vec<u32> {
        mem::replace(&mut self.items, Vec::with_capacity(16))
    }
}

let mut b = Batch { items: vec![1, 2, 3] };
let drained = b.flush();

assert_eq!(drained, vec![1, 2, 3]);
assert!(b.items.is_empty());
assert_eq!(b.items.capacity(), 16);

Same trick works for swapping in a String::with_capacity(...), a pre-allocated HashMap, or anything where the replacement’s shape is tuned for what comes next.

When to reach for which

mem::take when the type has a cheap, meaningful Default and you don’t care about the leftover. mem::replace when you need to control the replacement — an enum variant, a pre-sized collection, a sentinel value. Both are safe, both are O(1), and both read more clearly than the Option::take / unwrap dance.

#033 Mar 2026

33. std::mem::take

Ever tried to move a value out of a &mut reference? The borrow checker won’t let you — but std::mem::take will. It swaps the value out and leaves Default::default() in its place.

1
2
3
4
5
6
7
use std::mem;

let mut name = String::from("Ferris");
let taken = mem::take(&mut name);

assert_eq!(taken, "Ferris");
assert_eq!(name, ""); // left with String::default()

This is especially useful when working with enum state machines where you need to consume the current state:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
use std::mem;

enum State {
    Running(String),
    Stopped,
}

impl Default for State {
    fn default() -> Self { State::Stopped }
}

fn reset(state: &mut State) -> Option<String> {
    match mem::take(state) {
        State::Running(data) => Some(data),
        State::Stopped => None,
    }
}

Without mem::take, you’d need .clone() or unsafe gymnastics to get the value out. See also mem::replace for when you want to specify what to leave behind instead of using Default.