首页 > 解决方案 > 借款检查器抱怨多次借款,而只有一次借款会发生

问题描述

考虑以下代码(也可在操场上找到

pub trait TextStream {
    fn next_str(&mut self) -> Option<&str>;
}

pub struct FilterTextStream<T: TextStream> {
    inner: T,
    maxlen: usize,
}

impl<T: TextStream> TextStream for FilterTextStream<T> {
    fn next_str(&mut self) -> Option<&str> {
        match self.inner.next_str() {
            None => None,
            Some(txt) if txt.len() <= self.maxlen => {
                Some(txt) // <-- this does not compile
                //Some(unsafe {&*(txt as *const str)}) // <-- this fixes the problem
            }
            _ => self.next_str()
        }
    }
}

TextStream特征的工作方式类似于迭代器,只是&str它产生的 ' 没有重叠的生命周期。FilterTextStream像(专门的)过滤器迭代器一样工作。

但是,此代码无法编译,并出现以下错误:

error[E0499]: cannot borrow `*self` as mutable more than once at a time
  --> src/main.rs:18:18
   |
11 |     fn next_str(&mut self) -> Option<&str> {
   |                 - let's call the lifetime of this reference `'1`
12 |         match self.inner.next_str() {
   |               ---------- first mutable borrow occurs here
...
15 |                 Some(txt)
   |                 --------- returning this value requires that `self.inner` is borrowed for `'1`
...
18 |             _ => self.next_str()
   |                  ^^^^ second mutable borrow occurs here

令我惊讶的是,我看不出这是如何借用self两次的。我们要么在第 15 行返回,要么在第 18 行返回,所以两者中只有一个会发生。我的假设是这也不是一个真正的问题,但其中一种情况是借用检查器不够聪明。我错过了什么吗?

假设我是对的,我设法unsafe通过人为地“打破”生命周期依赖性来使用一个块(参见注释掉的第 16 行)来规避这个错误。任何人都可以看到更好的方法(即没有任何unsafe块)来编译这段代码吗?

标签: rustborrow-checker

解决方案


根据The Polonius Talk,rustc 目前将函数签名中的生命周期视为整个函数体中的生命周期。因此,如果我理解正确,那么 rustc 借用不同的匹配武器并不重要。

代码类型检查cargo +nightly rustc -- -Zpolonius意味着当 Polonius 功能完全集成时,代码应该在没有任何更改的情况下进行类型检查。

我找不到比unsafe在有问题的示例中使用 like 并添加评论说unsafe可以在某些时候删除更好的解决方法。


推荐阅读