是否可以编写一个调用BufRead :: fill_buf的函数,直到使用不安全的方法不再发生中断的错误为止?

war*_*ock 0 loops rust borrow-checker

是否可以编写一个函数,BufRead::fill_buf直到io::ErrorKind::Interrupted使用不安全方法调用该函数直到不再发生?

使用不安全的代码,它是:

use std::{
    io::{self, BufRead},
    slice,
};

fn fill_buf_and_ignore_interrupts(reader: &mut impl BufRead) -> io::Result<&[u8]> {
    let (buf_ptr, buf_len) = loop {
        match reader.fill_buf() {
            Ok(buf) => (buf.as_ptr(), buf.len()),
            Err(e) => {
                if e.kind() != io::ErrorKind::Interrupted {
                    return Err(e);
                }
            }
        }
    };
    Ok(unsafe { slice::from_raw_parts(buf_ptr, buf_len) })
}
Run Code Online (Sandbox Code Playgroud)

如果尝试使用returnbreak Ok(buf),则从借阅检查器收到错误消息:

error[E0499]: cannot borrow `*reader` as mutable more than once at a time
 --> src/lib.rs:8:15
  |
6 | fn fill_buf_and_ignore_interrupts(reader: &mut impl BufRead) -> io::Result<&[u8]> {
  |                                           - let's call the lifetime of this reference `'1`
7 |     let (buf_ptr, buf_len) = loop {
8 |         match reader.fill_buf() {
  |               ^^^^^^ mutable borrow starts here in previous iteration of loop
9 |             Ok(buf) => return Ok(buf),
  |                               ------- returning this value requires that `*reader` is borrowed for `'1`
Run Code Online (Sandbox Code Playgroud)

我试图用递归替换循环,但错误仍然存​​在。我也尝试过使用#![feature(nll)],但是它也不起作用。

Séb*_*uld 5

您不能,并且也不想出于以下突出显示的原因(它们与参考return或无关unsafe)。fill_buf由于文档中的一项重要警告,因此无法按您认为的方式工作:

返回内部缓冲区的内容,如果内部缓冲区为空,则从内部读取器中填充更多数据。

换句话说,在随后的通话fill_buf,而不consume会,如果性状正常执行,遵循在文档规定的合同无操作。因此,如果您在任何需要调用的地方忘记了该要求,则一无所有就会充满风险fill_buf

两种解决方案:

  • 如果你正在阅读到流的末尾(这是什么BufReader在不少其他语言一样),只是BufRead::read_to_end()BufRead::read_line()BufRead::read_until()。如果可以识别定界符,read_until则可以轻松地将其加工成可迭代的结构
  • 如果您尝试查看数据并可能等待更多,则需要实现自己的特征。这并不是经常需要的,因为大多数试图窥视流的人正在寻找一个Pattern或单个字节(BufRead覆盖)。

作为一个简短的摘要,请fill_buf不要执行您认为会做的事情,并且在不消耗缓冲区内部状态的情况下,无需多次调用它。如果您不尝试执行此操作,则的较低级别方法BufRead不是该工作的工具。

  • 有些地方有`BufRead`。这显然不是其中之一。 (6认同)
  • 因此,您告诉我,有一个目的是从`BufRead`读取单个任意大小的字节块,而随后即使`Read`也提供[这种行为](https://在read()上的doc.rust-lang.org/std/io/trait.Read.html#tymethod.read)上,不需要递归引用内部缓冲区,以至于您需要`BufRead`和`实施[this](https://play.rust-lang.org/?version=stable&amp;mode=debug&amp;edition=2018&amp;gist=828129ffd4acdd2ea201405db486b37e)不安全? (2认同)