我无法理解why这会导致错误:

#[derive(Debug)]
pub struct Node {
    next: Option<Box<Node>>,
}

pub fn print_root_or_next(root: &mut Node, try_next: bool) {
    let mut current = root;
    match &mut current.next {
        Some(node) => {
            if try_next {
                current = &mut *node;
            }
        }
        None => return,
    }

    println!("{:?}", current);
}
error[E0502]: cannot borrow `current` as immutable because it is also borrowed as mutable
  --> src/lib.rs:17:22
   |
8  |     match &mut current.next {
   |           ----------------- mutable borrow occurs here
...
17 |     println!("{:?}", current);
   |                      ^^^^^^^
   |                      |
   |                      immutable borrow occurs here
   |                      mutable borrow later used here

我看不出怎么会有相互冲突的借款;甚至错误信息似乎也表明两个借词是一个且相同的.这是借阅判断器的一个问题,还是这个示例在某些方面确实存在缺陷?

我对这个限制很感兴趣.我对实施情况了解不多,但考虑到基本if:

if try_next {
    current = &mut *current.next.as_mut().unwrap();
}

和基本match:

match &mut current.next {
    Some(node) => {
        current = &mut *node;
    }
    None => return,
}

甚至把它们颠倒过来:

if try_next {
    match &mut current.next {
        Some(node) => {
            current = &mut *node;
        }
        None => return,
    }
}

所有的工作,必须有一些东西,借阅判断是或是没有考虑到,与我的理解冲突,为什么原来的形式不工作.

推荐答案

我认为问题在于,current本身就是一个有条件的重新开始.

考虑这样一个简单的代码,它go 除了条件,但是使用了两个变量:

#[derive(Debug)]
pub struct Node {
    next: Option<Box<Node>>,
}

pub fn print_root_or_next(root: &mut Node) {
    let a = root;
    let b;
    match &mut a.next {
        Some(node) => {
            b = &mut *node;
        }
        None => return,
    }

    println!("{:?}", a);
    println!("{:?}", b);
}

这会失败,正如您预期的错误消息所示:

error[E0502]: cannot borrow `a` as immutable because it is also borrowed as mutable
  --> src/lib.rs:16:22
   |
9  |     match &mut a.next {
   |           ----------- mutable borrow occurs here
...
16 |     println!("{:?}", a);
   |                      ^ immutable borrow occurs here
17 |     println!("{:?}", b);
   |                      - mutable borrow later used here

也就是说,a是可变借来的,而借来的是因为b而保持活力的.所以你不能在b还活着的时候使用a.

如果对最后两行println!行重新排序,它编译时不会出现问题,因为词法生命周期:b被打印,然后被遗忘,从而释放借阅并再次使用a.

现在,看看另一个变体,与您的类似,但没有if:

pub fn print_root_or_next(root: &mut Node) {
    let mut c = root;
    match &mut c.next {
        Some(node) => {
            c = &mut *node;
        }
        None => return,
    }
    println!("{:?}", c);
}

它的编译也很好,因为当c被重新加载时,它会被重新分配.从这一点开始,它的工作原理与上一个示例的b相同.你可以自由使用b,禁止使用的是a,这里已经没有了.

回到你的代码:

pub fn print_root_or_next(root: &mut Node, test: bool) {
    let mut c = root;
    match &mut c.next {
        Some(node) => {
            if test {
                c = &mut *node;
            }
        }
        None => return,
    }
    println!("{:?}", c);
}

这里的问题是,当c被重新加载时,它是有条件地完成的,编译器不知道它将是哪一个,比如上面例子中的ab.所以它必须假设两者同时存在!但是从这个例子中我们看到,当b处于活动状态时,不能使用a,但是因为它们都是相同的值,所以这个值就不能再使用了.

当编译器抱怨这个奇怪的错误消息时:

17 | , current);
   | ^^^^^^^
   | |
   | immutable borrow occurs here
   | mutable borrow later used here

它实际上意味着:

17 | , current);
   | ^^^^^^^
   | |
   | immutable borrow occurs here if try_next is false
   | mutable borrow at the same time used here if try_next is true

我不知道这是否是编译器的一个限制,使用这个reference that conditionally reborrows itself实际上是安全的.也许这是一个限制,或者可能有一些微妙的,我不明白...我怀疑,如果包含多个条件或多个引用,允许这样做可能是不合理的.

Rust相关问答推荐

Rust,polars CSV:有没有一种方法可以从impll BufRead(或任何字节迭代器)中读取CSV?

有条件默认实现

为什么函数不接受选项T参数的所有权?

go 掉包装 struct 中的泛型

当两者都有效时,为什么Rust编译器建议添加';&;而不是';*';?

返回的future 不是`发送`

类型批注需要静态生存期

在本例中,为什么我不能一次多次borrow 可变变量?

如何go 除多余的(0..)在迭代中,当它不被使用时?

我如何使用AWS SDK for Rust获取我承担的角色的凭据?

使用关联类型重写时特征的实现冲突

如何将实现多个特征的 struct 传递给接受这些特征为&;mut?

为什么rustc会自动降级其版本?

try 实现线程安全的缓存

当锁被释放时,将锁包装到作用域中是否会发生变化?

std::vector::shrink_to_fit 如何在 Rust 中工作?

为什么不可变特征的实现可以是可变的?

打印 `format_args!` 时borrow 时临时值丢失

将 `&T` 转换为新类型 `&N`

具有生命周期和以后引用的可变方法