如何在 Rust 中清除或删除 io::stdin 缓冲区?

Jak*_*ell 2 rust

在开始学习 Rust 语言后,我一直在用 Rust 编写一个简单的基于文本的游戏,并且我尝试实现一个函数来等待用户按 Enter 键,然后再继续程序。

到目前为止,经过一些实验我已经做到了:

pub fn wait() {
    let mut stdin = io::stdin();
    let wait_string = &mut String::new();

    wait_string.clear();
    println!("\nPress Enter to Continue\n");
    io::stdout().clear();
    stdin.read_line(wait_string);
}
Run Code Online (Sandbox Code Playgroud)

然而,我的问题是,由于标准输入上的硬编码缓冲区,如果用户在显示消息之前按下 Enter 键,该函数将自动继续,而无需等待。

有针对这个的解决方法吗?或者使用 std::thread::sleep 的另一种方法会更好吗?如果这很容易解决或不可能解决,我深表歉意,我仍在 Rust 中找到立足点。

pro*_*-fh 5

您可以临时切换到底层文件描述符上的非阻塞操作,以便消耗在此wait()调用之前可能输入的所有内容,然后切换回阻塞操作以实际等待输入。

这个例子需要libccrate并且只能在 Unix 上运行(我想使用winapicrate在 Windows 上也可以完成类似的事情)。

pub fn change_blocking_fd(
    fd: std::os::unix::io::RawFd,
    blocking: bool,
) {
    unsafe {
        let flags = libc::fcntl(fd, libc::F_GETFL);
        libc::fcntl(
            fd,
            libc::F_SETFL,
            if blocking {
                flags & !libc::O_NONBLOCK
            } else {
                flags | libc::O_NONBLOCK
            },
        );
    }
}

pub fn wait() {
    use std::os::unix::io::AsRawFd;
    let stdin = std::io::stdin();
    change_blocking_fd(stdin.as_raw_fd(), false);
    let mut wait_string = String::new();
    while stdin.read_line(&mut wait_string).is_ok_and(|n_bytes| n_bytes > 0) {
        println!("discard: {:?}", wait_string); // debug purpose only
        wait_string.clear();
    }
    change_blocking_fd(stdin.as_raw_fd(), true);
    println!("\nPress Enter to Continue\n");
    stdin.read_line(&mut wait_string).expect("!!!");
}

fn main() {
    println!("enter a few lines during five seconds");
    std::thread::sleep(std::time::Duration::from_millis(5000));
    println!("~~~~ before wait() ~~~~");
    wait();
    println!("~~~~ after wait() ~~~~");
}
/*
enter a few lines during five seconds
aaa
zzz
eee
~~~~ before wait() ~~~~
discard: "aaa\n"
discard: "zzz\n"
discard: "eee\n"

Press Enter to Continue


~~~~ after wait() ~~~~
*/
Run Code Online (Sandbox Code Playgroud)