【问题标题】:Is there a standard way of discarding input in Rust?Rust 中是否有丢弃输入的标准方法?
【发布时间】:2016-09-06 14:24:12
【问题描述】:

在 Rust 中从 stdin 读取输入非常简单:

use std::io;

let mut some_string = String::new();
let _ = io::stdin().read_line(&mut some_string);

但有时您可能只想丢弃它而不在任何地方确认它或获取缓冲区,例如:

println!("Press Enter to close");
io::stdin().discard_input(); // discard_input() doesn't exist

它可以读取任意数量的字符,直到遇到\n,忽略它并且什么也不返回或io::Result。有没有标准的方法,还是我必须自己实现?我追踪了read_line 的实现到BufRead 实现的read_until,但我不确定从那里开始是否是个好主意。

【问题讨论】:

  • 您将无法单独使用stdin 获得“按任意键继续”行为。例如,当使用终端时,您将无法读取用户在用户按下“回车”之前输入的任何内容。
  • Enter 限制非常适合我的需要。但出于好奇,实现这一目标还需要什么?
  • 在 Rust 中从 stdin 读取也会读取按 Enter 产生的 \n 字符。所以你可以随时阅读something。您应该将其编辑到您的问题中 - 然后有人可以回答。关于评论中的问题:基本上是平台特定功能。
  • 需要一个合适的键盘 API。标准库中没有任何内容,但有各种第三方库。例如glutin。当然,您始终可以使用特定于平台的东西,例如 winapi crate 或适用于您平台的任何等价物。
  • @LukasKalbertodt:例如打电话给libcgetchar(),对吗?不过,我追求更简单的东西;我编辑了问题。

标签: io rust stdin


【解决方案1】:

您可以在标准输入上实现.discard_until_newline(),例如:

这应该是一个正确且高效的实现(使用缓冲区读取,但不将读取的部分复制到任何地方)。当然,如果您不期望任何长行并且一次只读取一个字节,那可能会简单得多。

use std::io::Stdin;
use std::io;
use std::io::prelude::*;

pub trait DiscardUntil {
    fn discard_until_newline(&mut self) -> Result<(), io::Error>;
}

impl DiscardUntil for Stdin {
    fn discard_until_newline(&mut self) -> Result<(), io::Error> {
        let mut buffered = self.lock();
        loop {
            let (consume, done) = {
                let data = try!(buffered.fill_buf());
                if data.is_empty() {
                    (0, true)
                } else if let Some(newline_pos) = data.iter().position(|b| *b == b'\n') {
                    (newline_pos + 1, true)
                } else {
                    (data.len(), false)
                }
            };
            buffered.consume(consume);
            if done {
                break;
            }
        }
        Ok(())
    }
}

fn main() {
    println!("hi");
    io::stdin().discard_until_newline().unwrap();
    println!("again");
    io::stdin().discard_until_newline().unwrap();
    println!("goodbye");
}

【讨论】:

    【解决方案2】:

    我对 bluss 的代码进行了实验,并且能够提出一个性能稍差的实现,并且不太适合某些极端情况(参见下面的 cmets),但更简单、更短:

    use std::io;
    use std::io::{Stdin, BufRead};
    
    pub trait DiscardUntil {
        fn discard_until_newline(&mut self) -> Result<(), io::Error>;
    }
    
    impl DiscardUntil for Stdin {
        fn discard_until_newline(&mut self) -> Result<(), io::Error> {
            let mut buffered = self.lock();
            let amount = {
                let data = try!(buffered.fill_buf());
                data.len()
            };
            buffered.consume(amount);
            Ok(())
        }
    }
    

    我欢迎尝试设计一个更简单的解决方案。

    【讨论】:

    • 您能详细说明一下吗?我在哪里冒险?如果我这样做会发生什么?
    • 当你消耗了所有的缓冲区,而不检查是否有不止一行被读入。 Fill buf 将尝试填充整个缓冲区(通常为 8K)。如果你这样做,会发生什么是你不真实的方法名称。
    • 有办法触发吗?我测试的时候做不到。
    • 无法触发不代表不存在。我更喜欢编写构造正确的程序,而不是“看起来是正确的”。另一种情况是您消耗少于一行。所以一种方法是插入 8KB 的数据而不使用换行符。要触发多行情况,我会尝试将多行文本粘贴到终端中。
    • 谢谢,我在这个答案中包含了这个信息。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-12-11
    • 1970-01-01
    • 1970-01-01
    • 2017-04-24
    • 2013-12-08
    • 2013-02-03
    相关资源
    最近更新 更多