代码之家  ›  专栏  ›  技术社区  ›  d33tah

是否可以在stdin.lines()中间执行另一次读取?

  •  2
  • d33tah  · 技术社区  · 6 年前

    请考虑以下代码:

    use std::io::{self, BufRead, Read};
    
    fn main() {
        let mut stdin = io::stdin();
    
        let mut content_length = 0;
        for line_wrapped in stdin.lock().lines() {
            let line = line_wrapped.unwrap();
            if line == "" {
                let mut buf = vec![0u8; content_length];
                stdin.read_exact(&mut buf).unwrap();
                print!("{:?}", buf);
            }
            if line.starts_with("Content-Length: ") {
                content_length = line
                    .split("Content-Length: ")
                    .nth(1)
                    .unwrap()
                    .parse()
                    .unwrap();
            }
        }
    }
    

    编译器输出:

    error[E0502]: cannot borrow `stdin` as mutable because it is also borrowed as immutable
      --> src/main.rs:11:13
       |
    7  |     for line_wrapped in stdin.lock().lines() {
       |                         ----- immutable borrow occurs here
    ...
    11 |             stdin.read_exact(&mut buf).unwrap();
       |             ^^^^^ mutable borrow occurs here
    ...
    22 |     }
       |     - immutable borrow ends here
    

    .lines() )?

    1 回复  |  直到 6 年前
        1
  •  2
  •   trent oli_obk    6 年前

    在同一流的缓冲读取和非缓冲读取之间进行交替可能非常棘手。如果你不必 lock lines() ,用于实现 StdinLock 可以消耗超过 \n read_exact 打电话的地点不对。

    所以你必须 只有一次,你必须打电话 准确阅读 在同一个缓冲读卡器上 Lines ,以确保没有丢失字节。乍一看,这似乎是不可能的: 行() self 按价值计算,所以一旦你调用它,就不能调用 在同一个物体上。但有一个小把戏你可以用。

    文件 BufRead contains 这条毯子 impl

    impl<'a, B: BufRead + ?Sized> BufRead for &'a mut B
    

    &mut 对实现的事物的引用 布弗雷德 实施 布弗雷德 . 所以你可以暂时 &穆特 您的参考 ,呼叫 行() 那个 ,放弃 及时地 准确阅读 有效载荷 buf &穆特 线 .

    has_header 指示是否中断外部循环。它不是很漂亮,但也许你可以用它。

    let stdin = io::stdin();
    let mut stdin_buf = stdin.lock();
    
    'record: loop {
        let mut content_length = 0;
        let mut has_header = false;
        'header: for line_wrapped in (&mut stdin_buf).lines() {
            let line = line_wrapped.unwrap();
            if line.starts_with("Content-Length: ") {
                content_length = line["Content-Length: ".len()..].parse().unwrap();
            }
            if line.is_empty() {
                has_header = true;
                break 'header;
            }
        }
        if has_header {
            let mut buf = vec![0u8; content_length];
            stdin_buf.read_exact(&mut buf).unwrap();
            println!("{:?}", buf);
        } else {
            break 'record;
        }
    }
    

    最后一点:现在还不清楚 Content-Length 标题不存在。如果原始代码起作用,它将重用先前定义的值(不管最后的内容长度是多少,或者第一条记录是0)。我的版本总是使用0。这是惯用的铁锈 Option 表示可能未初始化的值,例如 content_length ,因此将其初始化为 None 如果没有 内容长度