0

I am attempting to create a struct in Rust that has two methods. One method should return the item at the current position in a list, and the other method should move the current position to the next item and return the last item. The code I have written is as follows:

struct Item {
    value: i32,
}

struct A {
    position: usize,
    list: Vec<Item>,
}

impl A {
    fn current(&self) -> &Item {
        &self.list[self.position]
    }

    fn next(&mut self) -> &Item {
        let bar = self.current();
        self.position += 1;
        bar
    }
}

fn main() {
    let mut a = A { position: 0, list: vec![Item { value: 1 }] };
    a.next();
}

However, I am encountering this error when I try to compile it:

error[E0506]: cannot assign to `self.position` because it is borrowed
  --> src/main.rs:17:9
   |
15 |     fn next(&mut self) -> &Item {
   |             - let's call the lifetime of this reference `'1`
16 |         let bar = self.current();
   |                   -------------- `self.position` is borrowed here
17 |         self.position += 1;
   |         ^^^^^^^^^^^^^^^^^^ `self.position` is assigned to here but it was already borrowed
18 |         bar
   |         --- returning this value requires that `*self` is borrowed for `'1`

For more information about this error, try `rustc --explain E0506`.
error: could not compile `playground` (bin "playground") due to previous error

I don't believe that I borrowed self.position because I used it directly as an array index. Can you help me understand what mistake I made? Thank you in advance.

Yujia Sun
  • 1
  • 1
  • 3
    The call to `current()` will borrow the whole struct immutably, so you can't borrow `self.position` later mutably. You'll just have to "inline" the call to `current`. Unrelated: those methods should return `Option<&Item>` in case the list is empty. – isaactfa Jun 16 '23 at 16:09
  • @isaactfa Thanks for your reply. Does this mean that even though I just want to borrow a reference of an item in one of the struct instance's field `list`, I am borrowing a reference of the whole struct instance? – Yujia Sun Jun 16 '23 at 16:19
  • No, you can borrow fields separately, but that doesn't work across method calls. So it's fine to borrow `self.field` immutably and `self.list` mutably at the same time within `next`. But once you call `current`, Rust only knows that all of `self` is borrowed immutably, so you can't take out a mutable reference to it at the same time. – isaactfa Jun 16 '23 at 16:39
  • 1
    @isaactfa I may have understood it, but I would like it to be clearer. Can I understand it from this perspective: The method `fn current(&self) -> &Item` with lifetime annotations becomes `fn<'a> current(&'a self) -> &'a Item` This means that when the returned `&Item` value is in borrowed state, `self` is also in a borrowed state, and therefore cannot be modified? – Yujia Sun Jun 16 '23 at 17:14
  • Yes, that's right. – isaactfa Jun 16 '23 at 17:23

0 Answers0