向量 split_once 方法的生命周期问题

问题描述 投票:0回答:1

我正在尝试实现一个文件行读取器,它不会进行太多的检查和分配来加速某些文件的读取。

这应该是有效的,但是编译器抱怨借用 self.buffer 作为可变的,而在 read_line 方法的开头仍然借用为不可变的。这个问题似乎与生命周期有关,但我无法向编译器解释第一个借用被删除并且与 None => arm 无关了。

struct FastFileLinesReader<B: BufRead> {
    stream: B,
    buffer: Vec<u8>,
    cursor: usize,
}

impl<B: BufRead> FastFileLinesReader<B> {
    fn new(stream: B) -> Self {
        Self {
            stream,
            buffer: vec![1024],
            cursor: 0,
        }
    }

    fn read_line(&mut self) -> Option<&[u8]> {
        let line = {
            let remainder = &self.buffer[self.cursor..];
            remainder.split_once(|v| *v == b'\n' as u8)
        };
        match line {
            Some((line, _)) => {
                self.cursor += line.len() + 1;
                return Some(line);
            }
            None => {
                self.buffer.copy_within(self.cursor.., 0);
                self.cursor = 0;
                let n = self.stream.read(&mut self.buffer[self.cursor..]).ok()?;
                if n == 0 {
                    return None;
                }
                return self.read_line();
            }
        };
    }
}

错误:

error[E0502]: cannot borrow `self.buffer` as mutable because it is also borrowed as immutable
   --> src/bin/main.rs:110:17
    |
99  |     fn read_line(&mut self) -> Option<&[u8]> {
    |                  - let's call the lifetime of this reference `'1`
100 |         let line = {
101 |             let remainder = &self.buffer[self.cursor..];
    |                              ----------- immutable borrow occurs here
...
107 |                 return Some(line);
    |                        ---------- returning this value requires that `self.buffer` is borrowed for `'1`
...
110 |                 self.buffer.copy_within(self.cursor.., 0);
performance rust lifetime
1个回答
1
投票

@isaactfa 是对的,这种情况是借用检查器的一个已知限制,它错误地认为提前返回与函数的其余部分重叠。

在这种情况下,您可以通过避免从

.split_once
获得的引用来回避问题,而只需使用索引即可:

fn read_line(&mut self) -> Option<&[u8]> {
    let newline = self.buffer[self.cursor..].iter().position(|v| *v == b'\n' as u8);
    
    if let Some(idx) = newline {
        self.cursor += idx + 1;
        return Some(&self.buffer[self.cursor..][..idx]);
    } else {
        self.buffer.copy_within(self.cursor.., 0);
        self.cursor = 0;
        let n = self.stream.read(&mut self.buffer[self.cursor..]).ok()?;
        if n == 0 {
            return None;
        }
        return self.read_line();
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.