Deref

#176 Jun 2026

176. Option::as_deref — Stop Writing .as_ref().map(|s| s.as_str())

You have an Option<String>. The function next door takes Option<&str>. The chain you keep typing — .as_ref().map(|s| s.as_str()) — has a one-method replacement.

The pattern that keeps showing up

Borrowing the inside of an Option<String> looks like this:

1
2
3
4
let owned: Option<String> = Some("hello".to_string());

// Compare against a literal.
assert_eq!(owned.as_ref().map(|s| s.as_str()), Some("hello"));

as_ref() turns Option<String> into Option<&String>, then map reaches inside to pull out &str. Two methods, one closure, all just to borrow.

Option::as_deref collapses the whole thing:

1
2
let owned: Option<String> = Some("hello".to_string());
assert_eq!(owned.as_deref(), Some("hello"));

Same result, one call, no closure.

Why it works

as_deref is defined for any Option<T> where T: Deref. It calls Deref::deref on the inner value, so you get Option<&T::Target>:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
let s: Option<String> = Some("hi".to_string());
let v: Option<Vec<i32>> = Some(vec![1, 2, 3]);
let b: Option<Box<i32>> = Some(Box::new(7));

let s_ref: Option<&str> = s.as_deref();      // String -> str
let v_ref: Option<&[i32]> = v.as_deref();    // Vec<T> -> [T]
let b_ref: Option<&i32> = b.as_deref();      // Box<T> -> T

assert_eq!(s_ref, Some("hi"));
assert_eq!(v_ref, Some(&[1, 2, 3][..]));
assert_eq!(b_ref, Some(&7));

Anything that derefs works, including your own types — implement Deref and as_deref follows for free.

Where it actually saves you

The most common use is feeding a borrowed view into a function that wants the unsized form:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
fn greet(name: Option<&str>) -> String {
    match name {
        Some(n) => format!("hi {n}"),
        None => "hi stranger".to_string(),
    }
}

let stored: Option<String> = Some("alice".to_string());
assert_eq!(greet(stored.as_deref()), "hi alice");

let missing: Option<String> = None;
assert_eq!(greet(missing.as_deref()), "hi stranger");

The stored value stays untouched — as_deref only borrows.

There’s also as_deref_mut for the &mut version, and Result::as_deref / as_deref_mut for the same trick on Result:

1
2
3
let r: Result<String, ()> = Ok("ok".to_string());
let borrowed: Result<&str, &()> = r.as_deref();
assert_eq!(borrowed, Ok("ok"));

Takeaway

Whenever you catch yourself typing .as_ref().map(|x| x.as_str()) or .as_ref().map(|x| &**x), reach for .as_deref(). One method, no closure, and it works on anything that derefs.