Если мы запустим this, тогда мы правильно получим ошибку «не может назначить неизменяемое поле a.x
».Внутренняя изменчивость по сравнению с данными, скрывающимися для фиксации референта изменяемого заимствования
Если мы удалим два комментария //
и прокомментируем эту плохую строку, мы получим сообщение об ошибке «не может назначить данные в ссылке &
». Это имеет смысл, потому что &mut
не обеспечивает внутреннюю изменчивость. Мы можем reborrow a &A
свободно, поэтому это не должно давать mutable доступ, ala &&mut
is &&
.
Если удалить оба //
комментариев и /* */
комментариев, то все это собирает, позволяя плохую линию, нарушающий инвариант, a.x
никогда не должно быть направлены на что-либо другое.
pub struct A<'a> {
pub x: &'a mut [u8; 3],
}
fn main() {
let y = &mut [7u8; 3];
let /*mut*/ a = A { x: &mut [0u8; 3] };
a.x[0] = 3;
a.x = y; //// This must be prevented!
{
// let b = &/*mut*/ a;
// b.x[1] = 2;
}
println!("{:?}", a.x);
}
Как следует поддерживать этот инвариант x
не должен быть изменен? Мы могли бы сделать поле частным, предоставляя общедоступные методы разыменования, за исключением того, что писать конструкторы для A
недопустимы.
Мы можем избежать неприятного конструктора, сделав A
частным членом обертки struct AA(A)
, который сам использует общедоступные методы разыменования. Теперь AA
нуждается в тривиальном конструкторе, но он не нуждается в аргументах для всех полей A
, не влияет на порядок выполнения и т. Д. Это становится болезненным, если нам нужны некоторые черты, реализованные как для, так и для AA
.
Тем не менее, другим подходом было бы использование внутренней изменчивости, работая с Cell<A>
, обращаясь к нему с помощью Cell::replace
и вернув его позже. Это звучит очень проблематично, но показывает, что существует больше решений.
Любые очистители подходят?
Другой вариант - использовать «Ячейку» внутри массива. Вы попробовали это? –