Как правило, принудительно Type<&mut T>
вводить в Type<&T>
.
, например, рассмотрим этот тип оболочки, который реализован без какого-либо небезопасного кода и поэтому является надежным:
#[derive(Copy, Clone)]
struct Wrapper<T>(T);
impl<T: Deref> Deref for Wrapper<T> {
type Target = T::Target;
fn deref(&self) -> &T::Target { &self.0 }
}
impl<T: DerefMut> DerefMut for Wrapper<T> {
fn deref_mut(&mut self) -> &mut T::Target { &mut self.0 }
}
Этот тип имеет свойство, которое &Wrapper<&T>
автоматически разыменовывается до &T
, а &mut Wrapper<&mut T>
автоматически разыменовывается до &mut T
. Кроме того, Wrapper<T>
можно скопировать, если T
.
Предположим, что существует функция, которая может принять &Wrapper<&mut T>
и привести его к &Wrapper<&T>
:
fn downgrade_wrapper_ref<'a, 'b, T: ?Sized>(w: &'a Wrapper<&'b mut T>) -> &'a Wrapper<&'b T> {
unsafe {
// the internals of this function is not important
}
}
Используя эту функцию, можно получить изменяемую и неизменную ссылку на одно и то же значение одновременно:
fn main() {
let mut value: i32 = 0;
let mut x: Wrapper<&mut i32> = Wrapper(&mut value);
let x_ref: &Wrapper<&mut i32> = &x;
let y_ref: &Wrapper<&i32> = downgrade_wrapper_ref(x_ref);
let y: Wrapper<&i32> = *y_ref;
let a: &mut i32 = &mut *x;
let b: &i32 = &*y;
// these two lines will print the same addresses
// meaning the references point to the same value!
println!("a = {:p}", a as &mut i32); // "a = 0x7ffe56ca6ba4"
println!("b = {:p}", b as &i32); // "b = 0x7ffe56ca6ba4"
}
Пример полной игровой площадки
Это не допускается в Rust, приводит к неопределенному поведению и означает, что функция downgrade_wrapper_ref
в этом случае не работает. Могут быть и другие конкретные c случаи, когда вы, как программист, можете гарантировать, что этого не произойдет, но вам все равно потребуется реализовать его специально для этих случаев, используя код unsafe
, чтобы убедиться, что вы берете ответственность за предоставление этих гарантий.