In the below code, the compiler knows that &str
may theoretically get stored in B
and C
(theoretically; if it were &Option<str>
and not &Option<()>
).
It somehow detects the interior mutability of RefCell and Mutex and marks &mut x
as still being active.
It is also knows that it can't get stored in A
or D
.
How is this possible?
How would I do the same for MyContainer
?
use std::{cell::RefCell, sync::Mutex};
#[derive(Default)]
struct A<'a>(Option<&'a ()>);
impl<'a> A<'a> {
fn x(&self, _x: &'a mut str) {}
}
#[derive(Default)]
struct B<'a>(RefCell<Option<&'a ()>>);
impl<'a> B<'a> {
fn x(&self, _x: &'a mut str) {}
}
#[derive(Default)]
struct C<'a>(Mutex<Option<&'a ()>>);
impl<'a> C<'a> {
fn x(&self, _x: &'a mut str) {}
}
#[derive(Default)]
struct MyContainer<T> {
t: T,
}
#[derive(Default)]
struct D<'a>(MyContainer<Option<&'a ()>>);
impl<'a> D<'a> {
fn x(&self, _x: &'a mut str) {}
}
fn test() {
{
let mut x = String::new();
let a: A<'_> = Default::default();
a.x(&mut x);
a.x(&mut x); // OK
}
{
let mut x = String::new();
let b: B<'_> = Default::default();
b.x(&mut x);
b.x(&mut x); // Error: x already mutably borrowed in previous line
}
{
let mut x = String::new();
let c: C<'_> = Default::default();
c.x(&mut x);
c.x(&mut x); // Error: x already mutably borrowed in previous line
}
{
let mut x = String::new();
let d: D<'_> = Default::default();
d.x(&mut x);
d.x(&mut x); // OK
}
}