mercredi 9 juin 2021

What design pattern for encapsulation of mutable methods on self? [duplicate]

I'm trying to work out what Rust design pattern to use in the following scenario (my background is C++).

Any external consumer of the code should only instantiate the Manager struct and interact with its functions. Internally, the Manager is responsible for performing actions on the items under its control. In this case, I have two vectors of two different types of items. An externally facing function selects the relevant item from each of the vectors and attempts to perform some action.

  • Its desirable to encapsulate the implementation away from the consumer
  • There are two (or more) sets of items that need to have some level of interaction to perform the consumers need

The issue seems to be with putting everything under the Manager struct, but I can't see how to provide the desired encapsulation in another way.

struct BigItem1 {}
impl BigItem1 {
    pub fn do_something_else(&mut self) {
        // Do something that alters this BigItem1
    }
}

struct BigItem2 {}
impl BigItem2 {
    pub fn do_something(&self, my_big_item_1: &mut BigItem1) {
        // Do some things with this BigItem2

        // Make a change to the provided BigItem1
        my_big_item_1.do_something_else();

        // Do some more things with this BigItem2
    }
}

struct Manager {
    big_item_1_vec: Vec<BigItem1>,
    big_item_2_vec: Vec<BigItem2>,
}

impl Manager {
    fn big_item_1_mut(&mut self, big_item_1_index: usize) -> &mut BigItem1 {
        &mut self.big_item_1_vec[big_item_1_index]
    }

    fn big_item_2(&self, big_item_2_index: usize) -> &BigItem2 {
        &self.big_item_2_vec[big_item_2_index]
    }

    pub fn externally_facing_fn(&mut self, big_item_1_index: usize, big_item_2_index: usize) {
        let my_big_item_1_mut = &mut self.big_item_1_mut(big_item_1_index);
        let my_big_item_2 = &self.big_item_2(big_item_2_index);

        my_big_item_2.do_something(my_big_item_1_mut);
    }
}

The code fails to compile:

error[E0502]: cannot borrow `*self` as immutable because it is also borrowed as mutable
  --> src/lib.rs:36:30
   |
35 |         let my_big_item_1_mut = &mut self.big_item_1_mut(big_item_1_index);
   |                                      ---- mutable borrow occurs here
36 |         let my_big_item_2 = &self.big_item_2(big_item_2_index);
   |                              ^^^^ immutable borrow occurs here
37 | 
38 |         my_big_item_2.do_something(my_big_item_1_mut);
   |                                    ----------------- mutable borrow later used here

I understand why, but I'm trying to work out how I can solve this in a way that retains the desired encapsulation.

Aucun commentaire:

Enregistrer un commentaire