TL; DR То, что вы делаете, нарушает требование эксклюзивности для изменяемых ссылок, но вы можете использовать общие ссылки и внутреннюю изменчивость для создания API, который работает.
A &mut T
ссылка представляет эксклюзивный доступ к T
.Когда вы заимствуете объект с &mut
, этот объект не должен быть доступен (изменяемым или неизменным) через любую другую ссылку в течение срока действия заимствования &mut
.В этом примере:
let mut test = Test { value: 0 };
let mut unsafe_struct: UnsafeStruct;
unsafe_struct = UnsafeStruct::new(&mut test);
unsafe_struct.set_test_value(1);
test.value();
test.set_value(2);
unsafe_struct.test_value();
unsafe_struct
поддерживает заем &mut
test
в живых.Неважно, что внутри он содержит необработанный указатель;это не может содержать ничего.'a
в UnsafeStruct<'a>
продлевает срок действия заимствования, делая его неопределенным поведением для прямого доступа к test
до тех пор, пока unsafe_struct
не будет использован в последний раз.
В примере предполагается, что вы на самом делехотите общий доступ доступ к ресурсу (то есть общий доступ между test
и unsafe_struct
).Rust имеет общий ссылочный тип;это &T
.Если вы хотите, чтобы оригинал T
оставался доступным в течение срока действия заимствования, этот заем имеет для совместного использования (&
), а не эксклюзивный (&mut
).
Как вы изменяете что-то, если у вас есть общая ссылка?Использование внутренней изменчивости .
use std::cell::Cell;
pub struct Test {
value: Cell<u32>,
}
impl Test {
pub fn value(&self) {
println!("{}", self.value.get())
}
pub fn set_value(&self, value: u32) {
self.value.set(value);
}
}
pub struct SafeStruct<'a> {
test: &'a Test,
}
impl<'a> SafeStruct<'a> {
pub fn new(test: &'a Test) -> SafeStruct<'a> {
SafeStruct { test }
}
pub fn test_value(&self) {
println!("{}", self.test.value.get())
}
pub fn set_test_value(&self, value: u32) {
self.test.set_value(value);
}
}
Не осталось кода unsafe
- Cell
- безопасная абстракция.Вы также можете использовать AtomicU32
вместо Cell<u32>
для обеспечения безопасности потоков или, если реальное содержимое Test
более сложное, RefCell
, RwLock
или Mutex
.Все это абстракции, которые обеспечивают общую («внутреннюю») изменчивость, но они различаются по использованию.Для получения более подробной информации ознакомьтесь с документацией и ссылками ниже.
В качестве окончательного решения, если вам нужен общий изменяемый доступ к объекту без накладных расходов, и вы несете полную ответственность за обеспечение его правильности на своих плечах, вы можетеиспользуйте UnsafeCell
.Этот требует , требует использования unsafe
кода, но вы можете написать любой API, какой захотите.Обратите внимание, что все упомянутые мною безопасные абстракции построены с использованием UnsafeCell
внутри.Вы не можете иметь общую изменчивость без нее.
Ссылки