【问题标题】:Why can I not borrow a variable as mutable more than once at a time with a &mut Box<T> while &mut T works?为什么我不能在 &mut T 工作时使用 &mut Box<T> 一次多次借用可变变量?
【发布时间】:2018-05-08 15:56:33
【问题描述】:

我正在尝试在 Rust 中实现一个链表,但我在理解这两个函数之间的区别时遇到了一些麻烦:

enum List<T> {
    Nil,
    Cons(T, Box<List<T>>)
}

fn foo<T>(list: &mut Box<List<T>>) {
    match **list {
        List::Nil => return,
        List::Cons(ref mut head, ref mut tail) => {
            // ...
        }
    }
}

fn bar<T>(list: &mut List<T>) {
    match *list {
        List::Nil => return,
        List::Cons(ref mut head, ref mut tail) => {
            // ...
        }
    }
}

foo编译失败,报错:

error[E0499]: cannot borrow `list` (via `list.1`) as mutable more than once at a time
  --> src/main.rs:66:34
   |
66 |         List::Cons(ref mut head, ref mut rest) => {
   |                    ------------  ^^^^^^^^^^^^ second mutable borrow occurs here (via `list.1`)
   |                    |
   |                    first mutable borrow occurs here (via `list.0`)
...
69 |     }
   |     - first borrow ends here

但是,bar 可以完美编译和运行。为什么bar 有效,而foo 无效?我正在使用 Rust 1.25 版。

【问题讨论】:

    标签: rust


    【解决方案1】:

    这可以简化为

    fn foo(v: &mut Box<(i32, i32)>) {
        match **v {
            (ref mut head, ref mut tail) => {}
        }
    }
    

    fn foo(v: &mut Box<(i32, i32)>) {
        let (ref mut head, ref mut tail) = **v;
    }
    

    问题在于Box 是一个奇怪的介于两者之间的类型。

    在 Rust 的历史中,Box 是编译器的特例;它知道Box 的很多细节,但这意味着它是“神奇的”,没有其他人可以实现像Box 这样工作的东西。

    RFC 130 提议改变它;制作Box“只是另一种类型”。不幸的是,这还没有完全过渡。

    细节有细微差别,但基本上当前的借用检查器处理模式匹配语法,而不是语义。它需要这样做以防止一些不健全的问题。

    在未来,非词汇生命周期 (NLL) 会神奇地解决这个问题;你不必做任何事情(万岁!)。

    在此之前,您可以使用这个丑陋的 blob 显式返回 &amp;mut T

    match *&mut **list {
    

    或显式调用DerefMut

    match *std::ops::DerefMut::deref_mut(list) {
    

    但是,有very little reason to accept a &amp;mut Box&lt;T&gt;

    另见:

    【讨论】:

    • 谢谢!所以如果我理解正确,问题是* 运算符总是使用Deref::deref(),即使Box 是从可变引用中获得的?我注意到显式调用 *list.deref_mut() 也可以。
    • @AndrewSun 我澄清了我的一些糟糕的措辞。 * 可以根据上下文调用 derefderef_mut,但在这种情况下,它不能告诉它需要是 deref_mut
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-11-29
    • 1970-01-01
    • 2020-06-05
    相关资源
    最近更新 更多