Borrow Checker and Reference into Option

I have a linked list that looks as follows:

struct DataType;

#[derive(Copy, Clone)]
struct Node<'a> {
    data: &'a DataType,
    next: Option<&'a Self>,
}

Then I have a function that gives me some data that I want to add to the list. In fact, it returns an Option<DataType>, so it can also be that I don't have any data to add.

fn to_be_added() -> Option<DataType> {
    unimplemented!()
}

So now I have

let head: Node = ...;
let data: Option<DataType> = to_be_added();

and I want to add the data to the front of the list, or not add anything if it's None. So something like:

let new_head = match data {
    Some(inner_data) => Node {
        data: &inner_data,
        next: Some(&head),
    },
    None => head,
};

The problem is that this complains that inner_data doesn't live long enough.

On the one hand I can understand this, because inner_data is only temporarily existing "while I know that I'm in the Some(...) case". On the other hand, I don't see an issue with a reference pointing to the inner value of the Option, because it can be verified that this reference is only set when the Option is Some(...), and it's not mutable so this can't change. But I guess the borrow checker is not clever enough for this.

But how do I "conditionally add" my (optional) data then?

I don't have a "dummy"/default value for DataType or so.

I would be grateful for your suggestions! Thank you!

Full Source Code
struct DataType;

#[derive(Copy, Clone)]
struct Node<'a> {
    data: &'a DataType,
    next: Option<&'a Self>,
}

fn to_be_added() -> Option<DataType> {
    unimplemented!()
}

fn main() {
    // we are currently at some arbitrary head node
    let head = Node {
        data: &DataType,
        next: None,
    };

    // now we get some data which should be added to the linked list
    // or if it returns None, then nothing should be added
    let data: Option<DataType> = to_be_added();

    // so now let's compute the new head
    let new_head = match data {
        Some(inner_data) => Node {
            data: &inner_data,
            next: Some(&head),
        },
        None => head,
    };
}

Note: Please do not suggest to change my linked list implementation. This is not my implementation, but an interface from a library that I have to work with.

The data variable to be added was being moved/consumed by the match statement, which prevents storing a reference to data in the other struct. To avoid this you can match by reference instead of by value. You can do this in one of two ways:

let new_head = match &data {
                     ^

or

Some(ref inner_data) => Node { data: inner_data, next: Some(&head) },
     ^^^
1 Like

Thanks!! :slight_smile:

1 Like