借用检查器抱怨多次借用,而只有一次会发生

Borrow checker complains about multiple borrowing, when only one will ever occur

考虑以下代码(也available on the playground

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 trait 的工作方式类似于迭代器,除了它产生的 &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 行 return,要么我们在第 18 行 return,所以只有两者之一会发生。我的假设是这不是 真正的 问题,但其中一个案例是借用检查器不够聪明。我错过了什么吗?

假设我是对的,我设法使用 unsafe 块(请参阅注释掉的第 16 行)通过人为地“打破”生命周期依赖性来避免此错误。谁能找到更好的方法(即没有任何 unsafe 块)来编译此代码?

根据 The Polonius Talk rustc 当前将函数签名中的生命周期视为它们在整个函数体中都是有效的。所以,如果我目前理解的话,rustc 认为借用在不同的火柴臂上并不重要。

代码类型检查 cargo +nightly rustc -- -Zpolonius 这意味着当 Polonius 功能完全集成时,代码应该进行类型检查而不做任何更改。

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