Cannot assing to 'xxx' because it is borrowed

Good day,

Im new to rust, liking it quite abit, but running into some troubles.. i hope someone can explain abit to me why this is failing as i fail to see why it is failing, and so failing to see how to solve this.


struct List{
    list: Layer2
}

struct Layer1<'a>{
    item_1: &'a Layer2
}

struct Layer2{
    item_1: String
}

fn main(){
    
    let mut list = List{
        list: Layer2{item_1: "name".to_string()}
    };

    let test = Layer1{
        item_1: &list.list


    };

    println!("{:#?}",test);
    list.list.item_1 = "bla".to_string(); // cannot assign to 'list.list.item_1' because it is borrowed assignment to borrowd 'liust.list.item_1' occurs here
    println!("{:#?}",test);
}

when i remove the last println! statement it compiles else it gives me the following error.

error[E0506]: cannot assign to `list.list.item_1` because it is borrowed
   --> src/main.rs:449:5
    |
443 |         item_1: &list.list
    |                 ---------- borrow of `list.list.item_1` occurs here
...
449 |     list.list.item_1 = "bla".to_string();
    |     ^^^^^^^^^^^^^^^^ assignment to borrowed `list.list.item_1` occurs here
450 |
451 |     println!("{:#?}",test);
    |                      ---- borrow later used here

how would one deal with this sort of problem..?
kind regards

You're encountering some of the basic mechanics of references and borrowing. Namely, you can't hold onto a shared reference (&) to something (&list.list) while you overwrite part of it (list.list.item_1 = ...).

You can think of it as the reference forbidding the overwrite, or as the overwrite killing the reference.

Perhaps think of list.list having a compile-time read-write lock; you can have many read lock guards (&) at the same time, but can only write or have a write guard (&mut) when there are no read guards.


How one solves borrow errors is pretty specific to the problem and I suspect this example is too simplified to give a satisfying answer. I could say use a &mut and modify through that, but I suspect this won't really help in the wider context.

As a general note, references are more typically for short-term borrows than long-lived data structures; pointer-based data structures are much less common than in C, say. Perhaps Layer1 should own Layer2, but again, it's hard to say from the example.

1 Like

And when they're used, they often can be built on top of Box or Arc.

2 Likes

Good day!,
you ppl are quick in responding, very nice!

looking at your playground example, but this is not what im after..
let me explain abit better what im after..

i am working on a Sensor project that should drive some relays..
it uses a n amount of Sensors contained in a Sensors structure, this structure contains SensorData structure with the actual sensor data.. i also have n amount of relays inside a Relays structure. i want to connect SensorData to a specific relay struct, so when the sensor data changes, the relay struct will contain these changes as well as its pointing to the sensor data
memory..

im not sure this is best practice in rust though as it seems not very straight forward.
in the playground example you mutate the test structure itself, but in this case i would need it to change from the list itself. think of the list to be the same as the Sensors struct and and test being the Relays struct containing a pointer to the SensorData (layer2).

for now i solved it with using a channel enum, adding that to the SensorData and to RelayData. allows me to do a quick lockup. but this is not ideal. a pointer would be better. or at least from a standpoint of C. not sure about rust.

kind regards.

i will have to take a look if smart pointers can do this for me, i did use Arc for mutexes.
and cloned the Arc for threading.. i will have to play around with this a bit more. as i dont completely understand Arc. do you maybe have a example on how to do what i described above. with smart pointers.

kind regards.