想学习Rust吗? Ya rly!

我可以阻止FizzBu​​zz吗?不可以!

Gimme /bin/cat然后。但是rustc说哈哈!现在必须处理err0rz!

现在所有err0r handlurz,所以/bin/lolcat。 Rust sux还是OP sux?


普通的英语翻译:

想学习Rust,但是不想写FizzBu​​zz。写/bin/cat怎么样?但是对于每个函数调用,Rust坚持要求您对Result进行操作,这可能是错误的。事实证明,所有错误处理都使简单的任务变得复杂。出了什么问题?


// Using rustc 1.0.0-beta.3
use std::env;
use std::io::Read;
use std::io::Write;
use std::fs::File;
use std::path::Path;
use std::process;

macro_rules! println_stderr(
    ($($arg:tt)*) => (
        match writeln!(&mut ::std::io::stderr(), $($arg)* ) {
            Err(e) => panic!("Unable to write to stderr: {}", e),
            Ok(_) => {},
        }
    )
);

fn main() {
    let args: Vec<_> = env::args().collect();
    if args.len() < 2 {
        println_stderr!("Usage: {} GIMME_TEH_FILEZ",
                Path::new(&args[0]).file_name().unwrap().to_str().unwrap());
        process::exit(1);
    }

    let path = Path::new(&args[1]);
    let mut file = match File::open(path) {
        Err(e) => {
            println_stderr!("{}", e);
            process::exit(1);
        },
        Ok(f) => f,
    };

    let mut buf = String::new();
    match file.read_to_string(&mut buf) {
        Err(e) => {
            println_stderr!("{}", e);
            process::exit(1);
        },
        Ok(_) => {},
    }
    print!("{}", buf);
}


#1 楼


C会让您忽略错误并假装一切都很好。天真的cat会很短,但也不太可靠。编写良好的cat会使用返回的所有错误代码来产生有用的结果。
Python和类似语言在这些情况下会引发异常,从而导致您在天真的方法出错的情况下获得回溯;再次,编写良好的cat将手动处理所有这些异常,从而产生更整洁的结果。通过分解结果来获得所需的信息,这使您更像是Python等语言中的默认排列。错误处理的显式性质在某些地方可能会很痛苦(最明显的是对于简单的脚本),但是由于它的伸缩性很好,因此它通常会带来更可靠的结果。

必须意识到人们通常认为必须成功完成的这些常见任务确实存在失败的可能性。


写到stderr和stdout可能会失败。它们可能通过管道传输到只读文件,或者在尚未准备就绪或未满的设备上。例如,如果写入失败,则print!会恐慌。
通过使用String,您已经限制了lolcat仅使用UTF-8;如果传递非UTF-8文件,该文件会在您的脸上爆炸。您可能想用vec![]代替String::new()read_to_end代替read_to_stringstdout().write(&buf)代替print!("{}", buf)

宏可以很好地缓解这些麻烦。例如,存在try!,它在处理结果时效果很好;例如,如果重构代码以使所有重要内容都在一个函数中,然后该函数可以返回Result<(), io::Error>,则可以在所有容易出错的I / O操作上使用try!。实际上,您可以执行一些操作,例如编写新的宏以提供帮助,并提供更有用的信息来说明错误发生的位置。

这里的内容更像我将要写的;当然,主观各方面各有不同,我作了一些风格上的更改以符合我认为是更常见的标准样式: -override“> use std::env; use std::io::{Read, Write, stdout}; use std::fs::File; use std::path::Path; use std::process; macro_rules! println_stderr { ($($arg:tt)*) => { match writeln!(&mut ::std::io::stderr(), $($arg)*) { Err(e) => panic!("Unable to write to stderr: {}", e), Ok(_) => (), } } } macro_rules! try_or_die { ($e:expr, $err_msg:expr) => { match $e { Ok(x) => x, Err(e) => { println_stderr!(concat!($err_msg, ": {}"), e); process::exit(1); }, } } } fn main() { let args: Vec<_> = env::args().collect(); if args.len() < 2 { println_stderr!("Usage: {} GIMME_TEH_FILEZ", Path::new(&args[0]).file_name().unwrap().to_str().unwrap()); process::exit(1); } let path = Path::new(&args[1]); let mut file = try_or_die!(File::open(path), "failed to open input file"); let mut buf = vec![]; try_or_die!(file.read_to_end(&mut buf), "failed to read input file"); try_or_die!(stdout().write(&buf), "failed to write output"); }

(起初我有try_or_exit,但后来听起来更好。)