:https://github.com/baoyachi/rust-error-handle
15-20minRust``Rust
Rust
Rust``Rust
******unwrap()******panicRust
Rust``Rust
,
fn main() {
let path = "/tmp/dat";
println!("{}", read_file(path));
}
fn read_file(path: &str) -> String {
std::fs::read_to_string(path).unwrap()
}
thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: Os { code: 2, kind: NotFound, message: "No such file or directory" }', src/libcore/result.rs:1188:5
stack backtrace:
0: backtrace::backtrace::libunwind::trace
at /Users/runner/.cargo/registry/src/github.com-1ecc6299db9ec823/backtrace-0.3.40/src/backtrace/libunwind.rs:88
...
15: rust_sugar::read_file
at src/main.rs:7
16: rust_sugar::main
at src/main.rs:3
...
25: rust_sugar::read_file
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.
path
unwrap() rustOption``Result
unwrap() !
****bugpanic
**unwrap()**code review,
unwrap() unwrap()
demoDemo****, unwrap()
unit test****mock unwrap() unwrap()
unwrap()rust
unwrap() Rust
golang
package main
import (
"io/ioutil"
"log"
)
func main() {
path := "/tmp/dat" //
file, err := readFile(path)
if err != nil {
log.Fatal(err) //
}
println("%s", file) //
}
func readFile(path string) (string, error) {
dat, err := ioutil.ReadFile(path) //
if err != nil { //errnil
return "", err //nil,err
}
return string(dat), nil //err=nil,
}
2020/02/24 01:24:04 open /tmp/dat: no such file or directory
golang
err!=nil golang``if err!=nil``if err!=nil
golang``Rust
fn main() {
let path = "/tmp/dat"; //
match read_file(path) { //
Ok(file) => { println!("{}", file) } //OK
Err(e) => { println!("{} {}", path, e) } //Err
}
}
fn read_file(path: &str) -> Result<String,std::io::Error> { //Result
std::fs::read_to_string(path) //
}
No such file or directory (os error 2)
Rust``Result``enum
,
pub enum Result<T, E> {
/// Contains the success value
Ok(#[stable(feature = "rust1", since = "1.0.0")] T),
/// Contains the error value
Err(#[stable(feature = "rust1", since = "1.0.0")] E),
}
Result``Result``match``Result
Ok(Err)
golang``Rust
golang
fileerr``nil
,return
**** if err!=nil
Rust``Result``Result``Ok``Err``Result``Ok
,Err``return
: Ok or Err
if err!=nil
**** lint
bugRust``match
,match``match
golang``Rust``return
Rust
Rust``std::error::Error
trait
https://doc.rust-lang.org/std/error/trait.Error.html
pub trait Error: Debug + Display {
fn description(&self) -> &str {
"description() is deprecated; use Display"
}
#[rustc_deprecated(since = "1.33.0", reason = "replaced by Error::source, which can support \
downcasting")]
fn cause(&self) -> Option<&dyn Error> {
self.source()
}
fn source(&self) -> Option<&(dyn Error + 'static)> { None }
#[doc(hidden)]
fn type_id(&self, _: private::Internal) -> TypeId where Self: 'static {
TypeId::of::<Self>()
}
#[unstable(feature = "backtrace", issue = "53487")]
fn backtrace(&self) -> Option<&Backtrace> {
None
}
}
description()``impl Display
impl
, to_string()
cause()
1.33.0source()``impl
source()``Err``Some(e)
,None
Error``Error
,Error,None``None
****Error
Error,ErrorSome(err)
,****type_id()
backtrace()``unstable``Rust``stable
Error
impl std::fmt::Debugtrait,#[derive(Debug)]
error
std::fmt::Display
trait,**** fmt(...)
std::fmt::Debug``trait``#[derive(Debug)]
std::error::Error``trait
,error
****std::error::Error``source()
Rust
:CustomError
use std::error::Error;
/// Error,std::fmt::Debugtrait
#[derive(Debug)]
struct CustomError {
err: ChildError,
}
///Displaytraitfmt
impl std::fmt::Display for CustomError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "CustomError is here!")
}
}
///Errortrait,Error:ChildError,source(),Some(err)
impl std::error::Error for CustomError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
Some(&self.err)
}
}
/// Error,std::fmt::Debugtrait
#[derive(Debug)]
struct ChildError;
///Displaytraitfmt
impl std::fmt::Display for ChildError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "ChildError is here!")
}
}
///Errortrait,Error,source()
impl std::error::Error for ChildError {}
///Resulterror:CustomError
fn get_super_error() -> Result<(), CustomError> {
Err(CustomError { err: ChildError })
}
fn main() {
match get_super_error() {
Err(e) => {
println!("Error: {}", e);
println!("Caused by: {}", e.source().unwrap());
}
_ => println!("No error"),
}
}
ChildError``Error
,****source()``std::error::Error
CustomError``ChildError
,****source()
,OptionSome(&self.err)
Error: CustomError is here!
Caused by: ChildError is here!
Rust
Error
Result
(Ok)(Err)match
*
UTF8
u32
()
...
///
fn read_file(path: &str) -> Result<String, std::io::Error> {
std::fs::read_to_string(path)
}
/// utf8
fn to_utf8(v: &[u8]) -> Result<&str, std::str::Utf8Error> {
std::str::from_utf8(v)
}
/// u32
fn to_u32(v: &str) -> Result<u32, std::num::ParseIntError> {
v.parse::<u32>()
}
u32
unwrap()``bug
,panic
,match
OK,:
fn main() {
let path = "./dat";
match read_file(path) {
Ok(v) => {
match to_utf8(v.as_bytes()) {
Ok(u) => {
match to_u32(u) {
Ok(t) => {
println!("num:{:?}", u);
}
Err(e) => {
println!("{} {}", path, e)
}
}
}
Err(e) => {
println!("{} {}", path, e)
}
}
}
Err(e) => {
println!("{} {}", path, e)
}
}
}
///
fn read_file(path: &str) -> Result<String, std::io::Error> {
std::fs::read_to_string(path)
}
/// utf8
fn to_utf8(v: &[u8]) -> Result<&str, std::str::Utf8Error> {
std::str::from_utf8(v)
}
/// u32
fn to_u32(v: &str) -> Result<u32, std::num::ParseIntError> {
v.parse::<u32>()
}
match
****From
Error,error
ErrorError
Error****ErrorResult
Error
#[derive(Debug)]
enum CustomError {
ParseIntError(std::num::ParseIntError),
Utf8Error(std::str::Utf8Error),
IoError(std::io::Error),
}
impl std::error::Error for CustomError{
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match &self {
CustomError::IoError(ref e) => Some(e),
CustomError::Utf8Error(ref e) => Some(e),
CustomError::ParseIntError(ref e) => Some(e),
}
}
}
impl Display for CustomError{
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match &self {
CustomError::IoError(ref e) => e.fmt(f),
CustomError::Utf8Error(ref e) => e.fmt(f),
CustomError::ParseIntError(ref e) => e.fmt(f),
}
}
}
impl From<ParseIntError> for CustomError {
fn from(s: std::num::ParseIntError) -> Self {
CustomError::ParseIntError(s)
}
}
impl From<IoError> for CustomError {
fn from(s: std::io::Error) -> Self {
CustomError::IoError(s)
}
}
impl From<Utf8Error> for CustomError {
fn from(s: std::str::Utf8Error) -> Self {
CustomError::Utf8Error(s)
}
}
CustomError
Error
CustomError
Error
CustomError
Error From
trait,Error
CustomError
?
use std::io::Error as IoError;
use std::str::Utf8Error;
use std::num::ParseIntError;
use std::fmt::{Display, Formatter};
fn main() -> std::result::Result<(),CustomError>{
let path = "./dat";
let v = read_file(path)?;
let x = to_utf8(v.as_bytes())?;
let u = to_u32(x)?;
println!("num:{:?}",u);
Ok(())
}
///
fn read_file(path: &str) -> std::result::Result<String, std::io::Error> {
std::fs::read_to_string(path)
}
/// utf8
fn to_utf8(v: &[u8]) -> std::result::Result<&str, std::str::Utf8Error> {
std::str::from_utf8(v)
}
/// u32
fn to_u32(v: &str) -> std::result::Result<u32, std::num::ParseIntError> {
v.parse::<u32>()
}
#[derive(Debug)]
enum CustomError {
ParseIntError(std::num::ParseIntError),
Utf8Error(std::str::Utf8Error),
IoError(std::io::Error),
}
impl std::error::Error for CustomError{
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match &self {
CustomError::IoError(ref e) => Some(e),
CustomError::Utf8Error(ref e) => Some(e),
CustomError::ParseIntError(ref e) => Some(e),
}
}
}
impl Display for CustomError{
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match &self {
CustomError::IoError(ref e) => e.fmt(f),
CustomError::Utf8Error(ref e) => e.fmt(f),
CustomError::ParseIntError(ref e) => e.fmt(f),
}
}
}
impl From<ParseIntError> for CustomError {
fn from(s: std::num::ParseIntError) -> Self {
CustomError::ParseIntError(s)
}
}
impl From<IoError> for CustomError {
fn from(s: std::io::Error) -> Self {
CustomError::IoError(s)
}
}
impl From<Utf8Error> for CustomError {
fn from(s: std::str::Utf8Error) -> Self {
CustomError::Utf8Error(s)
}
}
fn main() -> Result<(),CustomError>{
let path = "./dat";
let v = read_file(path)?;
let x = to_utf8(v.as_bytes())?;
let u = to_u32(x)?;
println!("num:{:?}",u);
Ok(())
}
?``match``?
Result<(),CustomError>
Err``From``From``CustomError
From``?``match
****Err(e)``?
golang
:if err!=nil``?
Result``main
Result``main
Result``Result``unwrap()
Result
...
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_get_num() -> std::result::Result<(), CustomError> {
let path = "./dat";
let v = read_file(path)?;
let x = to_utf8(v.as_bytes())?;
let u = to_u32(x)?;
assert_eq!(u, 8);
Ok(())
}
}
`ResultResult
Err```,********
///
fn read_file(path: &str) -> std::result::Result<String, CustomError> {
let val = std::fs::read_to_string(path)?;
Ok(val)
}
/// utf8
fn to_utf8(v: &[u8]) -> std::result::Result<&str, CustomError> {
let x = std::str::from_utf8(v)?;
Ok(x)
}
/// u32
fn to_u32(v: &str) -> std::result::Result<u32, CustomError> {
let i = v.parse::<u32>()?;
Ok(i)
}
****Rust``Result
:
pub type IResult<I> = std::result::Result<I, CustomError>; ///ResultIResult
Result``IResult``std::result::Result``Error
///
fn read_file(path: &str) -> IResult<String> {
let val = std::fs::read_to_string(path)?;
Ok(val)
}
/// utf8
fn to_utf8(v: &[u8]) -> IResult<&str> {
let x = std::str::from_utf8(v)?;
Ok(x)
}
/// u32
fn to_u32(v: &str) -> IResult<u32> {
let i = v.parse::<u32>()?;
Ok(i)
}
std::result::Result<I, CustomError>
IResult<I>
OK
tuple (I,O)
pub type IResult<I, O> = std::result::Result<(I, O), CustomError>;
I,O,
fn foo() -> IResult<String, u32> {
Ok((String::from("bar"), 32))
}
Result
Rust``unwrap()``Result
,Option``Option
pub enum Option<T> {
/// No value
#[stable(feature = "rust1", since = "1.0.0")]
None,
/// Some value `T`
#[stable(feature = "rust1", since = "1.0.0")]
Some(#[stable(feature = "rust1", since = "1.0.0")] T),
}
Option``enum``None
,Some(T)
Some(T)``T
,unwrap()``unwrap()``panic
Ok,, Option``?``?
,
#[derive(Debug)]
enum Error {
OptionError(String),
}
impl std::error::Error for Error {}
impl std::fmt::Display for Error {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match &self {
Error::OptionError(ref e) => e.fmt(f),
}
}
}
pub type Result<I> = std::result::Result<I, Error>;
fn main() -> Result<()> {
let bar = foo(60)?;
assert_eq!("bar", bar);
Ok(())
}
fn foo(index: i32) -> Option<String> {
if index > 60 {
return Some("bar".to_string());
}
None
}
error[E0277]: `?` couldn't convert the error to `Error`
--> src/main.rs:22:22
|
22 | let bar = foo(60)?;
| ^ the trait `std::convert::From<std::option::NoneError>` is not implemented for `Error`
|
= note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait
= note: required by `std::convert::From::from`
error: aborting due to previous error
For more information about this error, try `rustc --explain E0277`.
error: could not compile `hyper-define`.
std::convert::From<std::option::NoneError>``NoneError``unstable``From
Error
Rust``Option``Result``Option``Option``ok_or()``Result
impl<T> Option<T> {
pub fn ok_or<E>(self, err: E) -> Result<T, E> {
match self {
Some(v) => Ok(v),
None => Err(err),
}
}
}
ok_or()
ErrorOption
->Result``Result
Option
?``Option``Result``Option
fn main() {
if let Some(v) = opt_val(60) {
println!("{}", v);
}
}
fn opt_val(num: i32) -> Option<String> {
if num >= 60 {
return Some("foo bar".to_string());
}
None
}
if let Some(v)``else``Option``Result
:
fn main() {
if let Ok(v) = read_file("./dat") {
println!("{}", v);
}
}
fn read_file(path: &str) -> Result<String, std::io::Error> {
std::fs::read_to_string(path)
}
Result``if let Ok(v)``Option``if let Some(v)
unwrap()
****
Result``?
,ErrorGlobalError
Error
std::convert::From<error::GlobalError<A>>` is not implemented for `error::GlobalError<B>
GlobalError
From<GlobalError>GlobalError
****
T``T
InnnerError
,ErrorGlobalError``Result<T,InnerError>
,Result<T,GlobalError>``From<T>
impl From<InnerError> for GlobalError {
fn from(s: InnerError) -> Self {
Error::new(ErrorKind::InnerError(e))
}
}
Error,Errorstd::result::Result<T,Err>``Err``From<T>``trait
Rust
https://github.com/Geal/nom
https://github.com/baoyachi/rust-error-handle/blob/master/src/demo_nom_error_handle.rs
ErrorRust
:https://github.com/baoyachi/rust-handle-error/tree/master/src