首页 > 解决方案 > 如何告诉借用检查器清除的 Vec 不包含借用?

问题描述

我正在处理一个庞大的 TSV(制表符分隔值)文件,并希望尽可能高效地执行此操作。为此,我想我会Vec通过在循环之前预先分配它来防止为每一行分配一个新的:

let mut line = String::new();
let mut fields = Vec::with_capacity(headers.len());
while reader.read_line(&mut line)? > 0 {
    fields.extend(line.split('\t'));
    // do something with fields
    fields.clear();
}

自然地,借用检查器不会被逗乐,因为我们正在覆盖linefields可能仍然有对它的引用:

error[E0502]: cannot borrow `line` as mutable because it is also borrowed as immutable
  --> src/main.rs:66:28
   |
66 |     while reader.read_line(&mut line)? > 0 {
   |                            ^^^^^^^^^ mutable borrow occurs here
67 |         fields.extend(line.split('\t'));
   |         ------        ---- immutable borrow occurs here
   |         |
   |         immutable borrow later used here

游乐场

这实际上不是问题,因为fields.clear();删除了所有引用,因此在循环开始时read_line(&mut line)调用时,fields实际上并没有从line.

但是我如何通知借阅检查员呢?

标签: rustborrow-checker

解决方案


您的问题与本文中描述的问题相似。

除了那里的答案(生命周期转换、参考单元)之外,根据您注释掉的复杂操作,您可能根本不需要存储对的引用line。例如,考虑以下对 Playground 代码的修改:

use std::io::BufRead;

fn main() -> Result<(), std::io::Error> {
    let headers = vec![1,2,3,4];
    let mut reader = std::io::BufReader::new(std::fs::File::open("foo.txt")?);
    let mut fields = Vec::with_capacity(headers.len());
    loop {
        let mut line = String::new();
        if reader.read_line(&mut line)? == 0 {
            break;
        }
        fields.push(0);
        fields.extend(line.match_indices('\t').map(|x| x.0 + 1));
        // do something with fields
        // each element of fields starts a field; you can use the next
        // element of fields to find the end of the field.
        // (make sure to account for the \t, and the last field having no
        // 'next' element in fields.
        fields.clear();
    }
    Ok(())
}

推荐阅读