【问题标题】:Why does this read input before printing?为什么这会在打印之前读取输入?
【发布时间】:2016-05-01 19:55:02
【问题描述】:

我在一些基本的 I/O 方面遇到了一些问题。具体来说,文本“请输入您的姓名”会写入输出我输入我的姓名并点击Enter

use std::io;

fn main() {
    print!("Please enter your name: ");

    let mut name = String::new();
    match io::stdin().read_line(&mut name) {
        Ok(_) => println!(""),
        Err(err) => println!("Could not parse input: {}", err)
    }

    println!("Hello, {}!", name.trim());
}

给出以下输出:

Compiling chat v0.1.0 (file:///home/marcus/dev/rust/chat)
  Running `target/debug/chat`
marcus
Please enter your name: 
Hello, marcus!

我输入第一个“marcus”的地方。为什么程序在等待输入之前不打印“请输入您的姓名”?


如果返回的ResultOk,是否可以“什么都不做”?在示例中,Ok() 表示我已将输入保存在变量名中。那太棒了。但是在这种情况下我该怎么处理Ok() =>

【问题讨论】:

    标签: rust


    【解决方案1】:

    为什么程序在等待输入之前不打印“请输入您的姓名”?

    嗯,它确实。只是出于性能原因,标准输出被缓冲了。写入完成,但它只是写入内存。如果您希望它实际显示给用户,则必须触发刷新。这可以通过编写换行符来完成,也可以通过显式完成:

    io::Write::flush(&mut io::stdout()).expect("flush failed!");
    
    // If you "use" `io::Write`...
    io::stdout().flush().expect("flush failed!");
    

    另外,如果返回的结果是好的,是否可以“什么都不做”?

    当然。只是……什么都不做。

    match io::stdin().read_line(&mut name) {
        Ok(_) => { /* nothing */ },
        Err(err) => println!("Could not parse input: {}", err)
    }    
    

    这里的相关要求是match 中的所有分支必须具有相同的结果类型。对于println!,结果为();除了一个空块(或另一个返回 () 的函数),您可以只使用文字:

    match io::stdin().read_line(&mut name) {
        Ok(_) => (),
        Err(err) => println!("Could not parse input: {}", err)
    }
    

    【讨论】:

    • 你应该提到if let Err(err) = io::stdin().read_line(&mut name) { println!("Could not parse input: {}", err); }
    【解决方案2】:

    这在documentation 中对print! 进行了解释。由于print! 不发出换行符并且stdout 是行缓冲的,因此您不会看到任何输出。您可以手动刷新标准输出:

    use std::io::{self, Write};
    
    print!("Please enter your name: ");
    io::stdout().flush();
    

    对于第二个问题,您始终可以明确返回单位:

    Ok(_) => (),
    

    所以你的程序变成了:

    use std::io::{self, Write};
    
    fn main() {
        print!("Please enter your name: ");
        io::stdout().flush();
    
        let mut name = String::new();
        match io::stdin().read_line(&mut name) {
            Ok(_) => (),
            Err(err) => println!("Could not parse input: {}", err)
        }
    
        println!("Hello, {}!", name.trim());
    }
    

    正如@Veedrac 在他们(现已删除)的评论中指出的那样,您可以在read_line 的结果上使用if let expression 代替match

    if let Err(err) = io::stdin().read_line(&mut name) {
        println!("Could not parse input: {}", err)
    }
    

    【讨论】:

    • 啊,我实际上已经尝试过了,但是由于它无法识别.flush() 函数而出现了一些错误。原来我错过了最后一部分use std::io::{self, Write};。您愿意详细说明{self, Write} 的含义吗?我似乎在文档中找不到它
    【解决方案3】:
    use std::io::{self, Write};
    
    fn main() {
        print!("Please enter your name: ");
        let _ = io::stdout().flush();
        // your io code
    }
    

    【讨论】:

    • 欢迎来到 Stack Overflow!仅包含代码的答案通常不会很受欢迎,因为它们没有解释任何内容。此外,这个问题已经有两个已经使用flush 的答案,所以不清楚这个新答案带来了什么好处。请edit您的答案描述更改以及它与现有答案的不同之处。
    • 忽略错误在 Rust 中相当罕见。通过详细说明为什么该决定对本案来说是一个好主意,可以进一步改进这个答案。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-05-19
    • 1970-01-01
    • 2011-02-11
    • 1970-01-01
    • 2016-01-18
    • 1970-01-01
    相关资源
    最近更新 更多