DEV Community

lv0senku
lv0senku

Posted on

Make (&Option).as_ref() easier

Option itself has a copy trait, but its behaviors depends on what it hold.

#[derive(Copy, PartialOrd, Eq, Ord, Debug, Hash)]
#[rustc_diagnostic_item = "Option"]
#[stable(feature = "rust1", since = "1.0.0")]
pub enum Option<T> {
    /// No value.
    #[lang = "None"]
    #[stable(feature = "rust1", since = "1.0.0")]
    None,
    /// Some value of type `T`.
    #[lang = "Some"]
    #[stable(feature = "rust1", since = "1.0.0")]
    Some(#[stable(feature = "rust1", since = "1.0.0")] T),
}
Enter fullscreen mode Exit fullscreen mode

Example

let x = Some(5);
let y = x; // copy x not move x
println!("{:?}", x); 
Enter fullscreen mode Exit fullscreen mode
let x = Some(Box::new(5));
let y = x; // moved here
println!("{:?}", x); // compile error
Enter fullscreen mode Exit fullscreen mode

So, when iterating over a linked list, you should use node.next.as_ref() rather than (&node.next).as_ref()

#[derive(Debug)]
struct Node {
    value: i32,
    next: Option<Box<Node>>,
}

fn main() {
    let mut head = Box::new(Node { value: 0, next: None });
    let second = Box::new(Node { value: 1, next: None });
    head.next = Some(second);

    let mut u = Some(&head);
    while let Some(v) = u {
        print!("{}->", v.value);
        // (&v.next).as_ref() is too verbose
        u = v.next.as_ref(); 
    }
    println!("None");

    println!("{:?}", &head);
}
Enter fullscreen mode Exit fullscreen mode

What as_ref does is take in Option<T>, then make it Option<&T>. This behavior cause a copy not move.

#[inline]
#[rustc_const_stable(feature = "const_option_basics", since = "1.48.0")]
#[stable(feature = "rust1", since = "1.0.0")]
pub const fn as_ref(&self) -> Option<&T> {
    match *self {
        Some(ref x) => Some(x),
        None => None,
    }
}
Enter fullscreen mode Exit fullscreen mode

Top comments (0)