I have above code where struct Foo whose member either can take Some(&mut i32) or None'.So i have marked it as Option<&'a mut i32>`.
Also I have a Trait which is marked with #[async_trait](because it has async fn fun() inside it) and it is implemented by another empty struct Bar.one of the argument to async fn fun() is Foo .
at line no 14 i want to change the value of val but it is failing with below message.
(Note:I'm forced to use as_ref()by compiler at line 14 )
14 | let val = arg.a.as_ref().expect("");
| --- help: consider changing this to be a mutable reference: `&mut &mut i32`
15 | **val = 100;
| ^^^^^^^^^^^ `val` is a `&` reference, so the data it refers to cannot be written
Instead of having arg:&'a mut Foo to fun() i want to have something like arg:mut Foo .
beacuse val will be of type &mut i32 (which is simpler to use) not &&mut i32. is this even possible in this case?
Is there a better way in rust to write the similar code ?any suggestions?
Note: this code is straightforward if i dont have #[async_trait] around Trait . I wonder what is the issue with async-trait
&&mut i32 is functionally the same as &&i32 (modulo possible variance differences, not sure if there are any) - the "shared" part of external reference overrides the "exclusive" part of the internal one. To change some value, you need to have exclusive (i.e. mutable) references in the whole chain. Not sure what stops you from using arg.a.as_mut().expect("") in line 14?
thanks!! I can use as_mut() . But here even after using as_mut(), type of val is &mut &mut (which is like double reference) what I want is something like &mut (single reference) . any suggestion on this?
Well, you can use take().expect("...") instead of as_mut().expect() to temporarily remove the reference from the Option, use it, then put it back. Not sure how this can be connected to async_trait, however, so it's possible that your case is more complicated and double-reference is unavoidable.
To be more precise, &'a &'b mut T is functionally the same as &'a &'a T, and in general there’s also a variance difference w.r.t. whether or not T is covariant in this type; though for T being i32 this variance doesn’t matter/apply.
Note that when x: &'a mut &'b mut T, you can dereference it to &mut **x which is a value of type &'a mut T. Rust even supports just writing *x for this operation ().
So let val: &mut i32 = *arg.a.as_mut().expect(""); works. There’s also the method Option::as_deref_mut which can dereference a pointer type in an &mut Option<…> for you. So let val: &mut i32 = arg.a.as_deref_mut().expect(""); works, too.
the so-called “reborrowing” that the extra “&mut *” does can happen implicitly ↩︎