1

Hopefully the title is accurate.

I would like to set a field on the Node struct that is inside of a vector. The node is a mutable reference, so I'm not sure why I can't assign to it. I'm guessing I am not properly unwrapping the Option?

Code example:


#[derive(Debug)]
enum ContentType {
    Big,
    Small,
}

#[derive(Debug)]
struct Node {
    content_type: Option<ContentType>
}

#[derive(Debug)]
struct List {
    nodes: Vec<Node>,
}

impl List {
    fn get_node(&self, index: usize) -> Option<&Node> {
        return self.nodes.get(index);
    }
}

fn main() {

    let list = List {
        nodes: vec![Node {content_type: None}]
    };
    
    let node = &mut list.get_node(0);
    
     println!("{:?}", list);
    
    if let Some(x) = node {
        x.content_type = Some(ContentType::Big)
    }
}

Playground: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=18bdaf8b903d57dfbf49ebfb3252cf34

Receiving this error:

cannot assign to `x.content_type` which is behind a `&` reference

puttputt
  • 1,259
  • 2
  • 14
  • 25
  • Rather than modifying the existing function to use `&mut`, you might want to make it a new function (e.g. `get_node_mut`) and keep both versions. – Solomon Ucko Nov 07 '20 at 01:16

2 Answers2

3

The error specifically refers to the return type of get_node, which is Option<&Node>. When you take the content out of the option here:

    if let Some(x) = node {
        x.content_type = Some(ContentType::Big)
    }

x becomes &Node, which is not a mutable reference.

You need to change get_node to return a mutable reference.

impl List {
    // Change to &mut self to borrow mutable items from self, and change the return type.
    fn get_node(&mut self, index: usize) -> Option<&mut Node> {
        return self.nodes.get_mut(index);
    }
}

fn main() {

    let mut list = List {
        nodes: vec![Node {content_type: None}]
    };
    
    // Move this print statement above get_node(), 
    // as you can't get a non mutable reference while you are still holding onto a mutable reference
    println!("{:?}", list);
    
    let node = list.get_node(0);
    
    if let Some(x) = node {
        x.content_type = Some(ContentType::Big)
    }
}

Playground

This means you can't get two mutable references to two different nodes at the same time however. See this question for a potential solution: How to get mutable references to two array elements at the same time?

8176135
  • 3,755
  • 3
  • 19
  • 42
0

It means what it says: get_node returns a Option<&Node> -- that's a non-mutable reference to a node. You can't mutate it.

Perhaps you meant to do

impl List {
    fn get_node(&mut self, index: usize) -> Option<&mut Node> {
        return self.nodes.get_mut(index);
    }
}

Then you can do

let mut list = List {nodes: vec![Node {content_type: None}]};

let node = list.get_node(0);

if let Some(x) = node {
    x.content_type = Some(ContentType::Big)
}
Mike Graham
  • 73,987
  • 14
  • 101
  • 130