algorithmrustdata-structureslinked-list

Constructing Linked List in Rust from head to tail without unwrap


It is said that unwrap is unsafe and it should be avoided if possible. While I was constructing a linked list, I found an unwrap inevitable.

My question is, is it possible to remove this unwrap or is there any theoretical reason that it is not possible?

(Updated the code to be an MRE for future reference.)

pub struct Node {
    pub value: i32,
    pub next: Option<Box<Node>>
}

impl Node {
    fn new(value: i32) -> Self {
        Node { next: None, value }
    }
}

fn vector_to_linked_list(v: &Vec<i32>) -> Option<Box<Node>> {
    let mut sentinel: Box<Node> = Box::new(Node {
        value: -1,
        next: None,
    });
    let mut current: &mut Box<Node> = &mut sentinel;
    for value in v.iter() {
        current.next = Some(Box::new(Node {
            value: *value,
            next: None,
        }));
        current = current.next.as_mut().unwrap();
    }
    sentinel.next
}

fn main() {
    let v: Vec<i32> = vec! [1, 2, 3];
    vector_to_linked_list(&v);
}

I am not expecting an answer which adds a meaningless branch like let-else or if-let.

Note: For the other way around, it seems that replace is useful.

self.root = Some(Box::new(Node {
    value: value,
    next: ::std::mem::replace(&mut self.root, None),
}));

Solution

  • You haven't posted an MRE so I can't verify whether this passes the borrow checker (I think it will), but this is exactly the kind of scenario where you would want to use Option::insert, which sets the Option to Some using the provided value, then returns an exclusive reference to that value:

    current = current.next.insert(Box::new(Node {
        value: value,
        next: None,
    }));
    

    I would prefer this since it's cleaner, but if your concern is that your code is less efficient or could panic at runtime, note that the optimizer will realize that the None case is impossible and elide the check and the panicking branch. In a simple contrived case comparing the two approaches using optimization level 1, the generated assembly is identical.