使用打印示例可以简化!和冲洗? [英] Simplification possible in example using print! and flush?

查看:86
本文介绍了使用打印示例可以简化!和冲洗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

几天前,我通过阅读官方文档开始对Rust进行编程.现在,我试图通过研究布莱恩·P·霍根(Brian P. Hogan)的《程序员的练习》一书来挑战我对Rust的理解.

I started programming Rust a couple of days ago by working through the official documentation. Now I'm trying to challenge my understanding of Rust by working through the book "Exercises for Programmers" by Brian P. Hogan (The Pragmatic Programmers).

第一个练习是编写一个程序,要求用户输入名称并使用该名称打印出问候语.输入,字符串连接和输出应分三个步骤完成.

The first exercise is to write a program that asks the user for a name and prints out a greeting using that name. Input, string concatenation and output should be done in three distinct steps.

What is your name? Patrick
Hello, Patrick, nice to meet you.

将在与初始提示相同的行中输入名称.这是我的解决方案:

The name will be entered at the same line as the initial prompt. Here's my solution:

use std::io;
use std::io::Write;

fn main() {
    print!("What is your name? ");
    match io::stdout().flush() {
        Ok(_) => print!(""),
        Err(error) => println!("{}", error),
    }
    let mut name = String::new();
    match io::stdin().read_line(&mut name) {
        Ok(_) => {
            name = name.trim().to_string();
            if name.len() > 0 {
                let greeting = "Hello, ".to_string() + &name + &", nice to meet you!".to_string();
                println!("{}", greeting);
            } else {
                println!("No name entered, goodbye.");
            }
        }
        Err(error) => println!("{}", error),
    }
}

print!宏实际上不会输出提示,直到我调用flush为止. flush需要错误处理,因此我需要同时处理OkErr情况.对于Ok,没有什么可做的,所以我只是print!一个空字符串.

The print! macro doesn't actually output the prompt until I call flush. flush needs error handling, so I need both to handle the Ok and the Err case. In case of Ok, there's nothing useful to do, so I just print! an empty string.

有没有更短的方法来解决这个问题?也许可以以某种方式跳过或简化错误处理,或者整个print!/flush方法是错误的. (一切正常,但毕竟我可以用C编写得短一些).

Is there a shorter way to handle this? Maybe the error handling can be skipped or simplified somehow, or the whole print!/flush approach is the wrong one. (Everything works fine, but I could write this shorter in C, after all...)

推荐答案

正如其他人所说,请务必阅读

As other people have said, make sure to read the error handling chapter.

在大多数情况下,您不想使用println!报告错误.您应该从函数中返回错误并让调用者处理该错误,或​​者应该使用panic!中止该线程,并可能中止进程.

In most cases, you don't want to use println! to report errors. Either you should return the error from your function and let the caller deal with it, or you should use panic! to abort that thread and potentially the process.

match io::stdout().flush() {
    Ok(_) => print!(""),
    Err(error) => println!("{}", error),
}

除了不打印任何内容(效率低下),您还可以...什么也不做:

Instead of printing nothing (which is inefficient), you can just... do nothing:

match io::stdout().flush() {
    Ok(_) => (),
    Err(error) => println!("{}", error),
}

由于您不关心成功案例,因此可以使用if let:

Since you don't care about the success case, you can use an if let:

if let Err(error) = io::stdout().flush() {
    println!("{}", error);
}

panic!替换println会更好:

if let Err(error) = io::stdout().flush() {
    panic!("{}", error);
}

这几乎完全是 Option::unwrap 可以(),除了它在存在时还会返回成功值:

This is almost exactly what Option::unwrap does (source), except it also returns the successful value when present:

pub fn unwrap(self) -> T {
    match self {
        Some(val) => val,
        None => panic!("called `Option::unwrap()` on a `None` value"),
    }
}

但是,使用 Option::expect ,它允许您指定其他错误消息:

However, it's even better to use Option::expect which allows you to specify an additional error message:

io::stdout().flush().expect("Unable to flush stdout");

应用两次:

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

fn main() {
    print!("What is your name? ");

    io::stdout().flush().expect("Unable to flush stdout");

    let mut name = String::new();
    io::stdin()
        .read_line(&mut name)
        .expect("Unable to read the line");

    let name = name.trim();

    if !name.is_empty() {
        println!("Hello, {}, nice to meet you!", name);
    } else {
        println!("No name entered, goodbye.");
    }
}

请注意,无需重新分配String,您只需阴影name,就无需使用format来打印内容.

Note that there's no need to re-allocate a String, you can just shadow name, and there's no need to use format just to print out stuff.

从Rust 1.26.0开始,您还可以选择从main返回Result:

Since Rust 1.26.0, you could also choose to return a Result from main:

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

fn main() -> Result<(), io::Error> {
    print!("What is your name? ");
    io::stdout().flush()?;

    let mut name = String::new();
    io::stdin().read_line(&mut name)?;

    let name = name.trim();

    if !name.is_empty() {
        println!("Hello, {}, nice to meet you!", name);
    } else {
        println!("No name entered, goodbye.");
    }

    Ok(())
}

但是我毕竟可以用C来写得更短...

but I could write this shorter in C, after all...

我会鼓励/挑战您尝试这样做.请注意,将检查此程序中的每个内存分配,以及处理标准输出的每个失败情况.许多人不知道C的printf 返回错误代码,您应该检查该错误代码.尝试输出到已关闭的管道作为示例.

I would encourage / challenge you to attempt this. Note that every memory allocation in this program is checked, as is every failure case dealing with the standard output. Many people are not aware that C's printf returns an error code that you should be checking. Try outputting to a pipe that has been closed for an example.

这篇关于使用打印示例可以简化!和冲洗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆