gpt4 book ai didi

rust - 为什么允许在一个表达式中同时具有数值类型向量的不可变和可变借用?

转载 作者:行者123 更新时间:2023-12-03 11:23:19 26 4
gpt4 key购买 nike

aVec<i32>它可以在一个表达式中可变且不可变地引用:

fn main() {
let mut a = vec![0, 1];
a[0] += a[1]; // OK
}

我认为这个编译是因为 i32工具 Copy ,所以我创建了另一种实现 Copy 的类型并像第一个示例一样编译它,但它失败了:

use std::ops::AddAssign;

#[derive(Clone, Copy, PartialEq, Debug, Default)]
struct MyNum(i32);

impl AddAssign for MyNum {
fn add_assign(&mut self, rhs: MyNum) {
*self = MyNum(self.0 + rhs.0)
}
}

fn main() {
let mut b = vec![MyNum(0), MyNum(1)];
b[0] += b[1];
}

playground

error[E0502]: cannot borrow `b` as immutable because it is also borrowed as mutable
--> src/main.rs:14:13
|
14 | b[0] += b[1];
| --------^---
| | |
| | immutable borrow occurs here
| mutable borrow occurs here
| mutable borrow later used here
  • 为什么我的 MyNumi32 的行为方式不同即使它实现了 Copy ?
  • 为什么可以在一个表达式中可变且不可变地引用向量?
  • 最佳答案

    我相信你在这里看到的是 primitive types实际上不要调用他们的 std::ops等价物。那些std::ops可能只是包含在无缝特征扩展等中。我认为博客文章 Rust Tidbits: What Is a Lang Item?部分解释了这一点。

    我导出了您示例的 MIR that works with primitive types .我有:

        bb5: {
    StorageDead(_9); // bb5[0]: scope 1 at src/main.rs:6:8: 6:9
    _10 = CheckedAdd((*_8), move _5); // bb5[1]: scope 1 at src/main.rs:6:5: 6:17
    assert(!move (_10.1: bool), "attempt to add with overflow") -> [success: bb6, unwind: bb4]; // bb5[2]: scope 1 at src/main.rs:6:5: 6:17
    }

    我在为出错的代码导出 MIR 时遇到了很多困难。在没有借用检查的情况下输出 MIR 对我来说是新的,我不知道该怎么做。

    This游乐场有一个非常相似的东西,但编译:)

    它给了我一个真正的电话 add_assign :

        bb3: {
    _8 = _9; // bb3[0]: scope 1 at src/main.rs:14:5: 14:9
    StorageDead(_10); // bb3[1]: scope 1 at src/main.rs:14:8: 14:9
    StorageLive(_11); // bb3[2]: scope 1 at src/main.rs:14:14: 14:22
    (_11.0: i32) = const 1i32; // bb3[3]: scope 1 at src/main.rs:14:14: 14:22
    // ty::Const
    // + ty: i32
    // + val: Value(Scalar(0x00000001))
    // mir::Constant
    // + span: src/main.rs:14:20: 14:21
    // + literal: Const { ty: i32, val: Value(Scalar(0x00000001)) }
    _7 = const <MyNum as std::ops::AddAssign>::add_assign(move _8, move _11) -> [return: bb5, unwind: bb4]; // bb3[4]: scope 1 at src/main.rs:14:5: 14:22
    // ty::Const
    // + ty: for<'r> fn(&'r mut MyNum, MyNum) {<MyNum as std::ops::AddAssign>::add_assign}
    // + val: Value(Scalar(<ZST>))
    // mir::Constant
    // + span: src/main.rs:14:5: 14:22
    // + literal: Const { ty: for<'r> fn(&'r mut MyNum, MyNum) {<MyNum as std::ops::AddAssign>::add_assign}, val: Value(Scalar(<ZST>)) }
    }

    原始案例如何通过借用检查器?自 add_assign未调用,则可以在需要可变引用之前删除不可变引用。 MIR 只是提前取消引用所需的位置并按值传递它。

        bb3: {
    _5 = (*_6); // bb3[0]: scope 1 at src/main.rs:6:13: 6:17
    StorageDead(_7); // bb3[1]: scope 1 at src/main.rs:6:16: 6:17
    ...
    }

    关于rust - 为什么允许在一个表达式中同时具有数值类型向量的不可变和可变借用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61732690/

    26 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com