Mutating a vector in a struct

Hello. I am new to Rust and just finished The Book. So pardon if this is too basic. I am attempting to implement a structure that stores a vector of data. I've simplified the code to it's most basic at this playground.

The code is reproduced here:

struct Category {
    num: u64
}

struct S {
    data: Option<Vec<Category>>
}

impl S {
    pub fn new() -> S {
        S {
            data: Some(Vec::new())
        }
    }
    
    pub fn insert(&mut self, category: Category) {
        match self.data {
            None => panic!("Cant add to non-existent vector."),
            Some(v) => {
                v.push(category);
            }
        }
    } 
}

The errors appear to be related to borrowing. Which confused me because I thought it would be sufficient to make the self pointer mutable:

error[E0507]: cannot move out of `self.data` as enum variant `Some` which is behind a mutable reference
  --> src/main.rs:17:15
   |
17 |         match self.data {
   |               ^^^^^^^^^
18 |             None => panic!("Cant add to non-existent vector."),
19 |             Some(v) => {
   |                  -
   |                  |
   |                  data moved here
   |                  move occurs because `v` has type `Vec<Category>`, which does not implement the `Copy` trait
   |
help: consider borrowing here
   |
17 |         match &self.data {
   |               +

error[E0596]: cannot borrow `v` as mutable, as it is not declared as mutable
  --> src/main.rs:20:17
   |
20 |                 v.push(category);
   |                 ^^^^^^^^^^^^^^^^ cannot borrow as mutable
   |
help: consider changing this to be mutable
   |
19 |             Some(mut v) => {
   |                  +++

Following the helpful advice of the compiler lead to a different and (somewhat more confusing) error. Playground here.

The error seems to suggest that its not even sufficient to make the vector itself mutable:

   Compiling playground v0.0.1 (/playground)
error[E0507]: cannot move out of `self.data` as enum variant `Some` which is behind a mutable reference
  --> src/main.rs:17:15
   |
17 |         match self.data {
   |               ^^^^^^^^^
18 |             None => panic!("Cant add to non-existent vector."),
19 |             Some(mut v) => {
   |                  -----
   |                  |
   |                  data moved here
   |                  move occurs because `v` has type `Vec<Category>`, which does not implement the `Copy` trait
   |
help: consider borrowing here
   |
17 |         match &self.data {
   |               +

Solving this would really help me understand the borrow checker. Thank you!

self.data still designates the field, not a reference to the field. If the LHS is a reference, then field access auto-dereferences, but it doesn't perform any auto-referencing. There's no "if self is a reference, then all fields are" kind of rule.

The cleanest solution would be to explicitly ask for a reference inside the option, using self.data.as_mut().

Alternatively, use mut ref in the pattern.

1 Like

I am not sure what you mean by the field access auto-references but doesnt perform any referencing. Do you mean that I can mutate the field itself but not the internals of a heap-stored type like vec?

No. I mean that self.data always has type Option<Vec_>>, regardless of whether self is a reference or not. (This has nothing to do with heap allocation at all.)

If you want a reference to the field, you need &(mut) self.data.

1 Like

Ah, I see. Thank you!

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.