当前位置: 首页 > 知识库问答 >
问题:

为什么借用检查器不允许第二个可变借用,即使第一个已经超出范围?

缪嘉志
2023-03-14

我知道借阅检查器不允许多个可变借阅。例如,下面的代码无效:

fn main() {
    let mut x = 42;
    let a = &mut x;
    let b = &mut x;
    println!("{} {}", a, b);
}

但是,如果第一次借款因超出范围而被放弃,第二次借款是有效的:

fn main() {
    let mut x = 1;
    {
        let a = &mut x;
        println!("{}", a);
    }
    let b = &mut x;
    println!("{}", b);
}

由于非词汇生存期(NLL),第一次借用甚至不必超出范围-借用检查器只要求不再使用它。因此,以下代码在2018年有效:

fn main() {
    let mut x = 1;

    let a = &mut x;
    println!("{}", a);

    let b = &mut x;
    println!("{}", b);
}

但我不明白为什么下面的代码无效:

use std::str::Chars;

fn main() {
    let s = "ab".to_owned();
    let mut char_iter = s.chars();

    let mut i = next(&mut char_iter);
    dbg!(i.next());

    let mut j = next(&mut char_iter);
    dbg!(j.next());
}

fn next<'a>(char_iter: &'a mut Chars<'a>) -> impl Iterator<Item = char> + 'a {
    char_iter.take_while(|&ch| ch != ' ')
}

编译错误信息:

error[E0499]: cannot borrow `char_iter` as mutable more than once at a time
  --> src/main.rs:10:22
   |
7  |     let mut i = next(&mut char_iter);
   |                      -------------- first mutable borrow occurs here
...
10 |     let mut j = next(&mut char_iter);
   |                      ^^^^^^^^^^^^^^ second mutable borrow occurs here
11 |     dbg!(j.next());
12 | }
   | - first borrow might be used here, when `i` is dropped and runs the destructor for type `impl std::iter::Iterator`

从错误消息中,我认为NLL可能还不支持这种情况。所以,我提前删除了i

use std::str::Chars;

fn main() {
    let s = "ab".to_owned();
    let mut char_iter = s.chars();

    {
        let mut i = next(&mut char_iter);
        dbg!(i.next());
    }

    let mut j = next(&mut char_iter);
    dbg!(j.next());
}

fn next<'a>(char_iter: &'a mut Chars<'a>) -> impl Iterator<Item = char> + 'a {
    char_iter.take_while(|&ch| ch != ' ')
}

(铁锈操场)

但我得到了一个更令人困惑的错误信息:

error[E0499]: cannot borrow `char_iter` as mutable more than once at a time
  --> src/main.rs:12:22
   |
8  |         let mut i = next(&mut char_iter);
   |                          -------------- first mutable borrow occurs here
...
12 |     let mut j = next(&mut char_iter);
   |                      ^^^^^^^^^^^^^^
   |                      |
   |                      second mutable borrow occurs here
   |                      first borrow later used here

为什么它会说第一次借用后来在这里使用,即使i以前已经被删除并超出了范围?

如果我将next函数的签名更改为:

fn next(char_iter: impl Iterator<Item = char>) -> impl Iterator<Item = char> {
    char_iter.take_while(|&ch| ch != ' ')
}

但我还是想理解为什么原来的next函数不起作用。

共有2个答案

闻人飞翼
2023-03-14

问题在于,您明确地告诉借阅检查器,ichar_iter在下一个块中的寿命一样长,方法是声明两者具有相同的寿命'a

fn next<'a>(char_iter: &'a mut Chars<'a>) -> impl Iterator<Item = char> + 'a {
    char_iter.take_while(|&ch| ch != ' ')
}

这意味着编译器认为

潘坚白
2023-03-14

impl Iterator实际上是一个具体的类型:Chars,它用Take虽然包装,所以您可以像这样重写您的方法(顺便说一句,一个有趣的任务是确定

fn next<'a>(
    char_iter: &'a mut Chars<'a>,
) -> TakeWhile<&'a mut Chars<'a>, impl FnMut(&char) -> bool> {
    char_iter.take_while(|&ch| ch != ' ')
}

现在您可能会看到,输出类型的寿命与输入相同,反之亦然。事实上,这个生命周期是从

fn next<'a, 'b: 'a>(
    char_iter: &'a mut Chars<'b>,
) -> TakeWhile<&'a mut Chars<'b>, impl FnMut(&char) -> bool> {
    char_iter.take_while(|&ch| ch != ' ')
}

 类似资料:
  • 如果我有一个封装两个成员的结构,并基于另一个成员更新其中一个,那么只要我这样做就可以了: 也就是说,当我直接提到self时。b 。但当我将do\u stuff()更改为以下内容时: 编译器抱怨:<代码>无法将`*self`借用为不可变,因为` self `。a `也被借用为可变的。 如果我需要执行比返回成员更复杂的操作来获取a.do\u something()的参数,该怎么办?我必须创建一个按值返

  • 可变数据可以使用 &mut T 进行可变借用。这叫做可变引用(mutable reference),并赋予了借用者读/写访问能力。相反,&T 通过不可变引用(immutable reference)来借用数据,借用者可以读数据而不能更改数据: #[allow(dead_code)] #[derive(Clone, Copy)] struct Book { // `&'static str`

  • 问题内容: 我想检查一个变量是否具有多个值之一。我对为什么在这种情况下不起作用感到困惑。我正在按照给出该示例的教程进行操作,但是当我尝试执行此操作时,它只会根据第一个值检查变量。我的支票怎么了? 问题答案: (“Jesse” or “jesse”) 上面的表达式测试是否评估为。如果是这样,则表达式将返回它;否则,它将返回。该表达式等同于编写: 因为是一个非空字符串,所以它将 始终 求值为并因此返回

  • 来自C++,我很惊讶这段代码在Rust中是有效的: 在C++中,您不能使用临时的地址,并且临时的时间不会超过它出现在其中的表达式。 临时工在铁锈中生活多长时间?而且由于只是一个借方,那么字符串的所有者是谁呢?

  • 我正试着用铁锈的雪球词干分析器板条箱来词干。这应该很简单,但借用检查器一直拒绝我的代码: 借用检查器说我在