Почему у меня может быть две ссылки на mut, если я использую черту From?

Код выглядит следующим образом: 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,
    };
}

Кто-нибудь может объяснить разницу?

Обратите внимание, что этот код имеет UB — он уже запускает Miri, как в сообщении, поэтому вопрос гораздо менее значим, чем может показаться.

Cerberus 22.02.2023 05:33

Да,_ignore: [u8; 9] должно быть _ignore: [u8; 7], но не влияет на вопрос

ViciOs 22.02.2023 07:32

Это все еще UB с [u8; 7] — проблема не только в несоответствии размеров, проблема в алиасинге изменяемых ссылок.

Cerberus 22.02.2023 08:20

Можете объяснить, что такое УБ? Я этого не вижу.

ViciOs 22.02.2023 12:07

Обе ссылки внутри RefInner указывают на одну и ту же память. Поскольку они изменяемы, согласно правилам Rust, это UB.

Cerberus 22.02.2023 13:20

Кодер (я) будет нести ответственность за это, так как используется небезопасный блок.

ViciOs 23.02.2023 04:03

Да, это то, на что я указываю - вы несете ответственность за то, чтобы не запускать этот код в производство, поскольку вы не знаете, во что он будет скомпилирован.

Cerberus 23.02.2023 04:23

Я знаю, что есть две ссылки, и ржавчина не позволяет этого, поэтому я задаю вопрос здесь. Этот код будет запущен в производство, и я думаю, что это нормально, даже если я не вижу ответа. Знать, что есть две ссылки на одну и ту же память, достаточно для написания кода C.

ViciOs 23.02.2023 04:40

Я имею в виду, что псевдоним изменяемой ссылки — это UB в Rust по определению. C его нет, да.

Cerberus 23.02.2023 04:46

Давайте продолжим обсуждение в чате.

ViciOs 23.02.2023 04:47
Ускорьте разработку веб-приложений Laravel с помощью этих бесплатных стартовых наборов
Ускорьте разработку веб-приложений Laravel с помощью этих бесплатных стартовых наборов
Laravel - это мощный PHP-фреймворк, используемый для создания масштабируемых и надежных веб-приложений. Одним из преимуществ Laravel является его...
Что такое двойные вопросительные знаки (??) в JavaScript?
Что такое двойные вопросительные знаки (??) в JavaScript?
Как безопасно обрабатывать неопределенные и нулевые значения в коде с помощью Nullish Coalescing
Создание ресурсов API Laravel: Советы по производительности и масштабируемости
Создание ресурсов API Laravel: Советы по производительности и масштабируемости
Создание API-ресурса Laravel может быть непростой задачей. Она требует глубокого понимания возможностей Laravel и лучших практик, чтобы обеспечить...
Как сделать компонент справочного центра с помощью TailwindCSS
Как сделать компонент справочного центра с помощью TailwindCSS
Справочный центр - это веб-сайт, где клиенты могут найти ответы на свои вопросы и решения своих проблем. Созданный для решения многих распространенных...
Асинхронная передача данных с помощью sendBeacon в JavaScript
Асинхронная передача данных с помощью sendBeacon в JavaScript
В современных веб-приложениях отправка данных из JavaScript на стороне клиента на сервер является распространенной задачей. Одним из популярных...
Как подобрать выигрышные акции с помощью анализа и визуализации на Python
Как подобрать выигрышные акции с помощью анализа и визуализации на Python
Отказ от ответственности: Эта статья предназначена только для демонстрации и не должна использоваться в качестве инвестиционного совета.
0
10
56
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ сводится к правилам исключения.

Ответ принят как подходящий

С вашей реализацией черты здесь с ellision времени жизни, время жизни ввода и вывода не пересекаются.

С помощью transmute() вы говорите компилятору игнорировать его.

Что касается функции с одним входом и одним выходом, компилятор назначает одинаковое время жизни.

Любой документ об этом? Какое 'b время жизни у реализации трейта? 'static?

ViciOs 22.02.2023 07:43

Наряду с 'a это «некоторая» жизнь, которая также может быть 'static, но не связана

vikram2784 22.02.2023 14:15
doc.rust-lang.org/nomicon/lifetime-elision.html
vikram2784 22.02.2023 16:56

Другие вопросы по теме