即使声明为可变的,变量也被认为是不可变的

Variable said to be immutable even if declared as mutable

我正在通过用布尔值向量表示数字来重新创建二进制算术运算。由于每个向量的大小可能不同,我做了一个函数来匹配每个向量的长度:

fn match_lengths(mut bit_vec0: Vec<bool>, mut bit_vec1: Vec<bool>) -> (Vec<bool>, Vec<bool>) {
    {
        let (mut shorter, longer) = if bit_vec0.len() < bit_vec1.len() {
            (&bit_vec0, &bit_vec1)
        } else {
            (&bit_vec1, &bit_vec0)
        };
        let bit_sign = match shorter.last() {
            Some(content) => *content,
            None => false,
        };

        for _ in shorter.len()..longer.len() {
            shorter.push(bit_sign);
        }
    }

    (bit_vec0, bit_vec1)
}

我收到错误

error[E0596]: cannot borrow immutable borrowed content `*shorter` as mutable
  --> src/main.rs:15:13
   |
15 |             shorter.push(bit_sign); // Error here
   |             ^^^^^^^ cannot borrow as mutable

尽管我用 mut 说明符声明了它。

shorter 的类型是 reference,更准确地说是 &Vec<bool>,这意味着它引用了 Vec<bool> 它是不允许突变1.

将变量声明为 mut shorter 只会使 shorter 变量可变,例如使用 shorter = ... 赋值使其引用不同的 Vec<bool>。无论变量的可变性如何,&Vec<bool> 类型的共享引用都不允许改变它所引用的对象。

您需要做的是使用 &mut bit_vec0&mut bit_vec1 创建类型 &mut Vec<bool> 的可变引用。此更改使代码可以编译,此时 shorter 不再需要 mut.

最后,这与问题无关,match_lengths 按值接受 bit_vec0bit_vec1,修改它们,并 returns 它们。虽然这确实有效,但接受可变引用更为惯用。这种方法对调用者来说更符合人体工程学,并且更清楚地表明该函数实际上并没有 "return" 任何东西,它实际上修改了现有对象。

经过这些修改,函数如下所示:

fn match_lengths(bit_vec0: &mut Vec<bool>, bit_vec1: &mut Vec<bool>) {
    let (shorter, longer) = if bit_vec0.len() < bit_vec1.len() {
        (bit_vec0, bit_vec1)
    } else {
        (bit_vec1, bit_vec0)
    };
    let bit_sign = match shorter.last() {
        Some(content) => *content,
        None => false,
    };
    for _ in shorter.len()..longer.len() {
        shorter.push(bit_sign);
    }
}

1 这听起来很像 C++ 的 const,但 Rust 中的保证甚至比 const 更强大:不仅共享(非 mut)引用不允许改变对象指的是,但也不是其他任何人! Rust 的编译器和运行时阻止创建对对象的 mut 引用,同时存在对该对象的任何共享引用。