Mutex for a struct with an array and index ->borrowing question

Hi all,
I again have a borrowing question, in know a way around, but I think that just shows I have not understood what is going on.... I isolated my code to this example:

use std::sync::{Mutex};

#[derive(Debug)]
struct MyStruct {
	a: [i32; 5],
	i: usize
}

impl MyStruct {
	fn new() -> MyStruct {
		MyStruct {a: [0;5], i: 3}
	}
}


fn main() {
	let mut myvar = MyStruct::new();
	println!("{:?}", myvar); 

	let my_mutex = Mutex::new(myvar);
	
	let mut my_new_var = my_mutex.lock().unwrap();
	my_new_var.a[my_new_var.i] = 1; //error[E0502]: cannot borrow `my_new_var` as immutable because it is also borrowed as mutable
	println!("{:?}", my_new_var); 
}

I think I understand vaguely why it is giving an error (the index in must not be a mutable var, though interesting enough without the Mutex it works).

My current workaround is to assign my_new_var.i to a local unmutable variable and use it instead. But I am sure there is a better way doing this. Can you enlighten me?

(using something like that in an application state variable while using Actix)

Thanks!

This is because of the Deref trait. my_new_var has the type MutexGuard<'_, MyStruct>, which implements both Deref and DerefMut. The Deref trait cannot provide access to disjoint fields on it's own, so you must acquire an exclusive reference explicitly before you can use disjoint fields.


fn main() {
	let mut myvar = MyStruct::new();
	println!("{:?}", myvar); 

	let my_mutex = Mutex::new(myvar);
	
	let mut my_new_var = my_mutex.lock().unwrap();
	let my_new_var = &mut *my_new_var;
	my_new_var.a[my_new_var.i] = 1; //works
	println!("{:?}", my_new_var); 
}

Thanks for your reply, I am not 100% sure I understand what you are saying, guess am at 95%.

If the Deref would not grant me access to disjoint fields (and if I understand that correctly), I would expect that this should also not work:

	let mut my_new_var = my_mutex.lock().unwrap();
	let local_var = my_new_var.i;
	my_new_var.a[local_var] = 1;

But that's my current workaround!? Here I am accessing also a field!? Would you know where my thinking goes wrong?

What I mean is that Deref* won't allow you to access disjoint fields mutably at the same time. This is because Deref* desugars to

let mut my_new_var = my_mutex.lock().unwrap();
my_new_var.a[my_new_var.i] = 1;

// becomes

let mut my_new_var = my_mutex.lock().unwrap();
DerefMut::deref_mut(&mut my_new_var).a[Deref::deref(&my_new_var).i] = 1;

// which is equivalent to

let mut my_new_var = my_mutex.lock().unwrap();
let __temp_0 = DerefMut::deref_mut(&mut my_new_var);
let __temp_1 = Deref::deref(&my_new_var);
__temp_0.a[__temp_1.i] = 1;

Which has an exclusive (mutable) reference overlapping with a shared reference. This is disallowed by rust's aliasing rules.

Wow, thanks a lot!

1 Like

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