Borrowing self while iterating over a field of self

How do you idiomatically iterate over a field in self while using other fields of self?

Example:

Some context

#[derive(Clone, Copy)]
struct Foo {
    foo: i32
}

struct FooContainer {
    items: Vec<Foo>,
    incremented: usize
}

impl FooContainer {
// here the actual example function
    fn increment_even_items_and_delete_the_ones_over_7(&mut self) {
        for item in &mut self.items {
            if item.foo % 2 == 0 {
                item.foo += 1;
                self.record_increment(); // cannot borrow because already borrowed 3 lines earlier (&mut self items)
            }
        }
        self.items.retain(|item| {
            item.foo <= 7
        });
    }
    
    fn new() -> Self {
        FooContainer { 
            items: (0..10).map(|i| Foo { foo: i }).collect(),
            incremented: 0
        }
    }
    
    fn record_increment(&mut self) {
        self.incremented += 1;
    }
}

One solution would be using a counter for the iteration:

    fn increment_even_items_and_delete_the_ones_over_7(&mut self) {
        for i in 0..self.items.len() {
            let item = &mut self.items[i];
            if item.foo % 2 == 0 {
                item.foo += 1;
                self.record_increment();
            }
        }
        self.items.retain(|item| {
            item.foo <= 7
        });
    }
}

Is there a more idiomatic way than the counter iteration?

One idea is to simply forego the record_increment() call altogether, like:

    fn increment_even_items_and_delete_the_ones_over_7(&mut self) {
        self.incremented += self
            .items
            .iter_mut()
            .map(|item| {
                if item.foo % 2 == 0 {
                    item.foo += 1;
                    1
                } else {
                    0
                }
            })
            .sum::<usize>();
        self.items.retain(|item| item.foo <= 7);
    }

Another is to make the methods borrow only the subset of fields that they actually need, and not the entirety of self.

Actually the question even a bit more general.

What is the idomatic way of implementing this pattern

for item in &self.items {
    self.do_something_with_item_that_mutates_self(*item);
}

I see the following solutions:

1. Clone self.items (overhead, violating zero cost demand)

for item in self.items.clone() {
    self.do_something_with_item_that_mutates_self(item);
}

2. C-style loop

for i in 0..self.items.len() {
    self.do_something_with_item_that_mutates_self(self.items[i]);
}

3. Ditch the method do_something_with_item_that_mutetes_self()

Instead write everything directly into the for loop. → Duplicated code if I need the method elsewhere.

What's the "That's the way to do it" way?

There is no idiomatic way to do this, because you're telling the compiler that you want to both iterate self.items through a shared reference and take an exclusive reference to self. There is a clear conflict of interest here.

The idiomatic way to rearrange your code so the compiler understands your intent is to only borrow disjoint fields. There has been some discussion on several options in the past. This thread is always a good reference: Blog post series: After NLL -- what's next for borrowing and lifetimes?

1 Like

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.