Код выглядит следующим образом: RefInner имеет два mut ref Inner и Inner.a, используйте черту From, код не содержит ошибок, но cp() покажет cannot borrow inner as mutable more than once at a time. деталь ошибки:
error[E0499]: cannot borrow `inner` as mutable more than once at a time
--> src/main.rs:40:12
|
37 | let b: RefInner = RefInner {
| _______________________-
38 | | // b: a.geta().into(), //no error
39 | | b: cp(inner.geta()),
| | ------------ first mutable borrow occurs here
40 | | a: &mut inner,
| | ^^^^^^^^^^ second mutable borrow occurs here
41 | | };
| |_____- first borrow later used here
For more information about this error, try `rustc --explain E0499`.
warning: `hello` (bin "hello") generated 1 warning
error: could not compile `hello` due to previous error; 1 warning emitted
#[derive(Debug)]
pub struct Inner {
pub a: u64,
pub b: u64,
}
pub struct RefInner<'a> {
pub a: &'a mut Inner,
pub b: &'a mut ResponseContext,
}
impl Inner {
fn geta(&mut self) -> &mut u64 {
&mut self.a
}
}
#[repr(C)]
#[derive(Debug)]
pub struct ResponseContext {
seq_id: u8,
_ignore: [u8; 7],
}
impl From<&mut u64> for &mut ResponseContext {
fn from(value: &mut u64) -> Self {
unsafe { std::mem::transmute(value) }
}
}
fn cp(n: &mut u64) -> &mut ResponseContext {
unsafe { std::mem::transmute(n) }
}
fn main() {
let mut inner: Inner = Inner { a: 1, b: 2 };
let b: RefInner = RefInner {
// b: a.geta().into(), //no error
b: cp(inner.geta()), //cannot borrow `inner` as mutable more than once at a time
a: &mut inner,
};
}
Кто-нибудь может объяснить разницу?
Да,_ignore: [u8; 9] должно быть _ignore: [u8; 7], но не влияет на вопрос
Это все еще UB с [u8; 7] — проблема не только в несоответствии размеров, проблема в алиасинге изменяемых ссылок.
Можете объяснить, что такое УБ? Я этого не вижу.
Обе ссылки внутри RefInner указывают на одну и ту же память. Поскольку они изменяемы, согласно правилам Rust, это UB.
Кодер (я) будет нести ответственность за это, так как используется небезопасный блок.
Да, это то, на что я указываю - вы несете ответственность за то, чтобы не запускать этот код в производство, поскольку вы не знаете, во что он будет скомпилирован.
Я знаю, что есть две ссылки, и ржавчина не позволяет этого, поэтому я задаю вопрос здесь. Этот код будет запущен в производство, и я думаю, что это нормально, даже если я не вижу ответа. Знать, что есть две ссылки на одну и ту же память, достаточно для написания кода C.
Я имею в виду, что псевдоним изменяемой ссылки — это UB в Rust по определению. C его нет, да.
Давайте продолжим обсуждение в чате.
Ответ сводится к правилам исключения.
С вашей реализацией черты здесь с ellision времени жизни, время жизни ввода и вывода не пересекаются.
С помощью transmute() вы говорите компилятору игнорировать его.
Что касается функции с одним входом и одним выходом, компилятор назначает одинаковое время жизни.
Любой документ об этом? Какое 'b время жизни у реализации трейта? 'static?
Наряду с 'a это «некоторая» жизнь, которая также может быть 'static, но не связана
Обратите внимание, что этот код имеет UB — он уже запускает Miri, как в сообщении, поэтому вопрос гораздо менее значим, чем может показаться.