1

I have the structs Foo and Bar. Foo contains an array of Bar and a private method to operate on Bar:

pub struct Bar;

pub struct Foo {
    bars: [Bar; 10],
}

impl Foo {
    pub fn process_all(&mut self) {
        for bar in self.bars.iter_mut() {
            self.process_single(bar);
        }
    }

    fn process_single(&mut self, bar: &mut Bar) {
        // ...
    }
}

This won't work because both self and one of its contained bars can't be borrowed at the same time.

error[E0499]: cannot borrow `*self` as mutable more than once at a time

One way of solving this in my case is an Option. I then have the ability to take ownership of the array in the function and then later giving it back to the struct after the process is done:

pub struct Bar;

pub struct Foo {
    bars: Option<[Bar; 10]>,
}

impl Foo {
    pub fn process_all(&mut self) {
        let bars = self.bars.take().unwrap();

        for bar in bars {
            self.process_single(bar);
        }

        self.bars = Some(bars);
    }

    fn process_single(&mut self, bar: &mut Bar) {
        // ...
    }
}

This feels very hacky; is there a better way?

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Geoxion
  • 448
  • 1
  • 4
  • 14
  • 3
    Niko wrote a [nice blog post](http://smallcultfollowing.com/babysteps/blog/2018/11/01/after-nll-interprocedural-conflicts/) about this and similar cases. – Sven Marnach Feb 14 '20 at 15:02
  • 3
    Do you have reasons to use `self` (or any mutable part other than the bar) in `process_single` ? If not you can just [make it a free function](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=3a313f2ca758bdf422e6adebf67689c2). – Denys Séguret Feb 14 '20 at 15:06
  • @SvenMarnach That is indeed a good post with the same problem. – Geoxion Feb 14 '20 at 15:08
  • @DenysSéguret I do, because in reality my Foo has more data that is touched. I guess I went a bit too much in an OOP solution... – Geoxion Feb 14 '20 at 15:09
  • 1
    TL;DR the duplicate: make more structs. Move `process_single` to a struct that contains what it needs to work, does not contain any `Bar`, and pass the `Bar` to it. Then your `Foo` holds the `Bar` array and the new type. – Shepmaster Feb 14 '20 at 15:23

0 Answers0