How to satisfy the borrow checker here?

My project is about deep learning neural networks and I am trying to create the layers and link them to another layer. Problem is, I need to borrow twice from the vector of layers, one of which is mutable borrow. How can this be done to satisfy the borrow checker?

pub fn new(
        input_height: usize,
        output_height: usize,
        hidden_height: usize, 
        hidden_width: usize, 
    ) -> Result<Self, Box<dyn Error>> {
       
        let mut rng = rand::thread_rng();
        let mut layers = Vec::<Layer>::with_capacity(hidden_width + 2);
        
        layers.push(Layer::new(input_height, None, &mut rng));
        for _ in 0..hidden_width {
            layers.push(Layer::new(hidden_height, layers.last(), &mut rng))
        }
        layers.push(Layer::new(output_height, layers.last(), &mut rng));

        Ok(Model(layers))
    }

I get the error:

error[E0502]: cannot borrow `layers` as mutable because it is also borrowed as immutable
30 |             layers.push(Layer::new(hidden_height, layers.last(), &mut rng))
   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-------------^^^^^^^^^^^^
   |             |                                     |
   |             |                                     immutable borrow occurs here
   |             mutable borrow occurs here
...
34 |         Ok(Model(layers))
   |         ----------------- returning this value requires that `layers` is borrowed for `'a`

1 Like

What’s the type signature of Layer::new? And the definition of the Layer struct? Does it have a lifetime argument?


From this error message, it seems like Layer has a lifetime argument, Layer<'a>, and Layer::new takes a Option<&'a Layer<'a>> reference to a “previous layer”, to be stored in the newly created layer.

Such structs are very hard to construct in Rust, since the ownership story for this “previous layer” is unclear - fields containing references are usually to be avoided in all situations where the struct isn’t just a transient, short-lived value.

3 Likes
pub struct Layer<'a> {
    nodes: Vec<Node>,
    linked_layer: Option<&'a Layer<'a>>
}

impl<'a> Layer<'a> {
    pub fn new(length: usize, linked_layer: Option<&'a Layer>, rng: &mut ThreadRng) -> Self {
        Layer { 
            nodes: vec![Node::new(rng); length],
            linked_layer
        }
    }

    pub fn link(&mut self, other: &'a Layer, rng: &mut ThreadRng) {
        for node in self.iter_mut() {
            node.weights = vec![rng.gen(); other.len()];
        }
        self.linked_layer = Some(other);
    }

So… possible solutions include having Layer not store the “linked_layer” at all, and having this relation be implicit from the context (the Vec<Layer> it’s contained in), as it seems you always want to relate it to the previous element in this Vec, anyways.

Alternatively, you could try working with shared ownership via Vec<Rc<Layer>> (or with Arc if multi-threaded access is needed) and linked_layer would be an Rc<Layer> - either way would be an approach to eliminate the lifetime parameter of the struct Layer. Using Rc/Arc does introduce a degree of immutability to the data here, I don’t know if that’s intended - if the shared data should also be mutated, then shared mutability via RefCell is an option, but that’s a bit more tedious, and in such a case, you should re-evaluate whether other options (such as the first one I mention in this answer) couldn’t work.


Edit: A possible variation on the “always implicitly link consider the previous element in the Vec to be linked” approach, in case this assumption doesn’t hold true, would be to store merely the index of the linked layer in the same Vec<Layer> vector, assuming that linked layers always reside inside of the same Model.

1 Like

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.