为什么在打印之前要读取输入?

28

我在一些基本的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() 意味着我已经将输入保存在变量 name 中。这很好。但在这种情况下,我该如何处理 Ok() =>

3个回答

32

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

实际上,程序确实已经打印了该信息。只是出于性能考虑,标准输出被缓冲了。写操作已经完成,但它只是写入了内存。如果你想让它真正显示给用户看,你需要触发刷新。这可以通过写入换行符或显式执行来完成:

io::Write::flush(&mut io::stdout()).expect("flush failed!");

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

此外,如果返回的Result是Ok状态,是否有可能“什么也不做”?

当然可以。只需...什么也不做。

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

这里的相关要求是在一个match中,所有的 arms 都必须具有相同的结果类型。对于println!来说,它的结果是();除了空块(或者另一个返回()的函数)之外,你可以直接使用字面量:

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

4
你应该提到 if let Err(err) = io::stdin().read_line(&mut name) { println!("Could not parse input: {}", err); } - Veedrac

26

这在print!的文档中有解释。由于print!不会输出换行符,且标准输出是行缓冲的,您将看不到任何输出。您可以手动刷新标准输出:

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在他们(现在已删除的)评论中指出的那样,您可以使用一个if let表达式代替对read_line结果的match

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

1
啊,我其实已经尝试过那个了,但是因为没有识别出.flush()函数,所以出现了一些错误。结果发现我漏掉了最后的use std::io::{self, Write};部分。你能详细解释一下{self, Write}代表什么吗?我在文档中似乎找不到相关内容。 - mnordber

-1
use std::io::{self, Write};

fn main() {
    print!("Please enter your name: ");
    let _ = io::stdout().flush();
    // your io code
}

2
欢迎来到Stack Overflow!仅包含代码的答案通常不受欢迎,因为它们没有解释任何内容。此外,这个问题已经有两个使用了flush的答案,所以不清楚这个新答案带来了什么好处。请编辑您的答案,描述更改及其与现有答案的区别。 - Shepmaster
1
在 Rust 中忽略错误是相当罕见的。详细说明为什么在这种情况下做出这个决定是一个好主意,可以进一步改善这个答案。 - Shepmaster

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接