郑州新密网站建设,设计师导航网站大全,临清住房建设网站,上海网站建设招标在Rust中#xff0c;将错误分为两种#xff0c;可恢复错误和不可恢复错误。所谓可恢复错误就是指类似于文件未找到这类错误#xff0c;一般需要将它们报告给用户并再次尝试进行操作#xff0c;而不可恢复错误往往就是Bug#xff0c;需要停止程序的运行。 
1、不可恢复错误…在Rust中将错误分为两种可恢复错误和不可恢复错误。所谓可恢复错误就是指类似于文件未找到这类错误一般需要将它们报告给用户并再次尝试进行操作而不可恢复错误往往就是Bug需要停止程序的运行。 
1、不可恢复错误与panic! 
当代码中出现没有预料到的错误时Rust提供了一个特殊的宏panoc!程序会在panic!宏执行时打印一段错误提示信息展开并清理当前的调用栈然后退出程序的执行。 当panic发生时程序会默认开始栈展开。这意味着Rust会沿着调用栈的反向顺序遍历所有调用函数并依次清理这些函数中的数据。但是为了支持这种遍历和清理操作我们需要在二进制中存储许多额外信息。 
2、可恢复错误与Result 
在程序的调试中有些错误没有严重到需要停止整个程序的运行例如尝试打开一个文件而文件不存在的情况。这种情况可以使用Result类型来处理。在Result枚举中定义了两个变体——OK和Err。示例 
enum ResultT,E{OK(T),Err(E),
}这里的T和E都是泛型T代表了OK变体中包含的值的类型该变体中的值会在执行成功时返回E代表了Err变体中包含的错误类型该变体会在执行失败时返回。 
(1)、匹配不同的错误 
由于在编程时会遇到不同的错误那么就可以根据错误的种类来执行不同的操作。示例 
use std::fs::File;
use std::io::ErrorKind;
fn main() {let f  File::open(hello.txt);let f  match f {Ok(file)  file,Err(error)  match error.kind() {ErrorKind::NotFound  match File::create(hello.txt) {Ok(fc)  fc,Err(e)  panic!(Tried to create file but there was a problem:{:?}, e),},other_error  panic!(There was a problem opening the file: {:?},other_error),},};
}File::open返回的Err变体中的错误值类型是定义在某个标准库中的结构体类型io::Error。这个结构体拥有一个被称作kind的方法可以通过调用它来获得 io::ErrorKind 值。这个io::ErrorKind枚举是由标准库提供的它的变体被用于描述io操作所可能导致的不同错误。这里使用的变体是ErrorKind::NotFound它用于说明我们尝试打开的文件不存在。所以我们不但对变量f使用了match表达式还在内部对error.kind()使用了match表达式。 
(2)、失败时触发panic的快捷方式unwrap和expect 
虽然使用match运行得很不错但使用它所编写出来的代码可能会显得有些冗长且无法较好地表明其意图。类型ResultT, E本身也定义了许多辅助方法来应对各式各样的任务。当Result的返回值是Ok变体时unwrap就会返回Ok内部的值。而当Result的返回值是Err变体时unwrap则会替我们调用panic! 宏。示例 
use std::fs::File;
fn main() {let f  File::open(hello.txt).unwrap();
}还有另外一个被称作expect的方法它允许我们在unwrap的基础上指定panic! 所附带的错误提示信息。使用expect并附带上一段清晰的错误提示信息可以阐明你的意图并使你更容易追踪到panic的起源。示例 
use std::fs::File;
fn main() {let f  File::open(hello.txt).expect(Failed to open hello.txt);
}使用expect所实现的功能与unwrap完全一样要么返回指定文件句柄要么触发panic! 宏调用。唯一的区别在于expect触发panic! 时会将传入的参数字符串作为错误提示信息输出而unwrap触发的panic! 则只会携带一段简短的默认信息。 
(3)、传播错误 
编写的函数中包含了一些可能会执行失败的调用时除了可以在函数中处理这个错误还可以将这个错误返回给调用者让他们决定应该如何做进一步处理。这个过程也被称作传播错误在调用代码时它给了用户更多的控制能力。与编写代码时的上下文环境相比调用者可能会拥有更多的信息和逻辑来决定应该如何处理错误。 传播错误的模式在Rust编程中非常常见所以Rust专门提供了一个问号运算符?来简化它的语法。示例 
use std::io;
use std::io::Read;
use std::fs::File;
fn read_username_from_file() - ResultString, io::Error {let mut f  File::open(hello.txt)?;let mut s  String::new();f.read_to_string(mut s)?;Ok(s)
}通过将放置于Result值之后我们实现了与使用match表达式来处理Result时一样的功能。假如这个Result的值是Ok那么包含在Ok中的值就会作为这个表达式的结果返回并继续执行程序。假如值是Err那么这个值就会作为整个程序的结果返回如同使用了return一样将错误传播给调用者。 match表达式与运算符的一个区别被运算符所接收的错误值会隐式地被from函数处理这个函数定义于标准库的From trait中用于在错误类型之间进行转换。当运算符调用from函数时它就开始尝试将传入的错误类型转换为当前函数的返回错误类型。当一个函数拥有不同的失败原因却使用了统一的错误返回类型来同时进行表达时这个功能会十分有用。只要每个错误类型都实现了转换为返回错误类型的from函数?运算符就会自动处理所有的转换过程。 注?运算符只能被用于返回Result的函数。 
3、要不要使用panic! 
什么时候应该使用panic!而什么时候又应该返回Result呢代码一旦发生panic就再也没有恢复的可能了。只要你认为自己可以代替调用者决定某种情形是不可恢复的那么就可以使用panic!而不用考虑错误是否存在可以恢复的机会。当你选择返回一个Result值时你就将这种选择权交给了调用者。调用者可以根据自己的实际情况来决定是否要尝试进行恢复或者干脆认为Err是不可恢复的并使用panic! 来将可恢复错误转变为不可恢复错误。因此我们会在定义一个可能失败的函数时优先考虑使用Result方案。