rust 如果使用From trait,为什么可以有两个mut引用?

gfttwv5a  于 2023-02-23  发布在  其他
关注(0)|答案(2)|浏览(190)

代码如下所示,RefInner有两个mut引用InnerInner.a,使用From特征代码没有错误,但cp()将显示cannot borrow内部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,
    };
}
    • 有人能解释其中的区别吗**
bqujaahr

bqujaahr1#

在trait实现中使用lifetime省略号,输入和输出的生命周期是disjoint
也就是说,在您情况下,它是impl<'a, 'b> From<&'a mut u64> for &'b mut ResponseContext
使用transmute(),您是在告诉编译器使用ignore it
对于具有一个输入和一个输出的函数,编译器分配相同的生存期.
基本上就是
如果执行impl<'a> From<&'a mut u64> for &'a mut ResponseContext,它的行为将类似于函数cp()

roejwanj

roejwanj2#

答案归结为省略规则。
当你有impl From<&mut A> for &mut B时,这个实现头被去糖化为impl<'from, 'to> From<&'from mut A> for &'to mut B,也就是说,它允许将 any reference(不管多短)转换为 any reference(不管多长)。一般来说,这两个生命周期必须连接起来,因为否则方法体将无法编译,但是在这里你已经强制借用检查器接受了transmute的这个通用实现。
但是,当您使用fn(&mut A) -> &mut B时,它会以更具体的方式进行去糖处理-即,去糖处理为fn<'lt>(&'lt mut A) -> &'lt mut B,即输入和输出的生命周期是相等的-因此,只要输出引用存在,原始可变引用就会被“锁定”,从而阻止任何其他使用。

相关问题