Movatterモバイル変換


[0]ホーム

URL:


Module result

std

Moduleresult 

1.0.0 ·Source
Expand description

Error handling with theResult type.

Result<T, E> is the type used for returning and propagatingerrors. It is an enum with the variants,Ok(T), representingsuccess and containing a value, andErr(E), representing errorand containing an error value.

enumResult<T, E> {Ok(T),Err(E),}

Functions returnResult whenever errors are expected andrecoverable. In thestd crate,Result is most prominently usedforI/O.

A simple function returningResult might bedefined and used like so:

#[derive(Debug)]enumVersion { Version1, Version2 }fnparse_version(header:&[u8]) ->Result<Version,&'staticstr> {matchheader.get(0) {None=>Err("invalid header length"),Some(&1) =>Ok(Version::Version1),Some(&2) =>Ok(Version::Version2),Some(_) =>Err("invalid version"),    }}letversion = parse_version(&[1,2,3,4]);matchversion {Ok(v) =>println!("working with version: {v:?}"),Err(e) =>println!("error parsing header: {e:?}"),}

Pattern matching onResults is clear and straightforward forsimple cases, butResult comes with some convenience methodsthat make working with it more succinct.

// The `is_ok` and `is_err` methods do what they say.letgood_result:Result<i32, i32> =Ok(10);letbad_result:Result<i32, i32> =Err(10);assert!(good_result.is_ok() && !good_result.is_err());assert!(bad_result.is_err() && !bad_result.is_ok());// `map` and `map_err` consume the `Result` and produce another.letgood_result:Result<i32, i32> = good_result.map(|i| i +1);letbad_result:Result<i32, i32> = bad_result.map_err(|i| i -1);assert_eq!(good_result,Ok(11));assert_eq!(bad_result,Err(9));// Use `and_then` to continue the computation.letgood_result:Result<bool, i32> = good_result.and_then(|i|Ok(i ==11));assert_eq!(good_result,Ok(true));// Use `or_else` to handle the error.letbad_result:Result<i32, i32> = bad_result.or_else(|i|Ok(i +20));assert_eq!(bad_result,Ok(29));// Consume the result and return the contents with `unwrap`.letfinal_awesome_result = good_result.unwrap();assert!(final_awesome_result)

§Results must be used

A common problem with using return values to indicate errors isthat it is easy to ignore the return value, thus failing to handlethe error.Result is annotated with the#[must_use] attribute,which will cause the compiler to issue a warning when a Resultvalue is ignored. This makesResult especially useful withfunctions that may encounter errors but don’t otherwise return auseful value.

Consider thewrite_all method defined for I/O typesby theWrite trait:

usestd::io;traitWrite {fnwrite_all(&mutself, bytes:&[u8]) ->Result<(), io::Error>;}

Note: The actual definition ofWrite usesio::Result, whichis just a synonym forResult<T,io::Error>.

This method doesn’t produce a value, but the write mayfail. It’s crucial to handle the error case, andnot writesomething like this:

usestd::fs::File;usestd::io::prelude::*;letmutfile = File::create("valuable_data.txt").unwrap();// If `write_all` errors, then we'll never know, because the return// value is ignored.file.write_all(b"important message");

If youdo write that in Rust, the compiler will give you awarning (by default, controlled by theunused_must_use lint).

You might instead, if you don’t want to handle the error, simplyassert success withexpect. This will panic if thewrite fails, providing a marginally useful message indicating why:

usestd::fs::File;usestd::io::prelude::*;letmutfile = File::create("valuable_data.txt").unwrap();file.write_all(b"important message").expect("failed to write message");

You might also simply assert success:

assert!(file.write_all(b"important message").is_ok());

Or propagate the error up the call stack with?:

fnwrite_message() -> io::Result<()> {letmutfile = File::create("valuable_data.txt")?;    file.write_all(b"important message")?;Ok(())}

§The question mark operator,?

When writing code that calls many functions that return theResult type, the error handling can be tedious. The question markoperator,?, hides some of the boilerplate of propagating errorsup the call stack.

It replaces this:

usestd::fs::File;usestd::io::prelude::*;usestd::io;structInfo {    name: String,    age: i32,    rating: i32,}fnwrite_info(info:&Info) -> io::Result<()> {// Early return on errorletmutfile =matchFile::create("my_best_friends.txt") {Err(e) =>returnErr(e),Ok(f) => f,    };if letErr(e) = file.write_all(format!("name: {}\n", info.name).as_bytes()) {returnErr(e)    }if letErr(e) = file.write_all(format!("age: {}\n", info.age).as_bytes()) {returnErr(e)    }if letErr(e) = file.write_all(format!("rating: {}\n", info.rating).as_bytes()) {returnErr(e)    }Ok(())}

With this:

usestd::fs::File;usestd::io::prelude::*;usestd::io;structInfo {    name: String,    age: i32,    rating: i32,}fnwrite_info(info:&Info) -> io::Result<()> {letmutfile = File::create("my_best_friends.txt")?;// Early return on errorfile.write_all(format!("name: {}\n", info.name).as_bytes())?;    file.write_all(format!("age: {}\n", info.age).as_bytes())?;    file.write_all(format!("rating: {}\n", info.rating).as_bytes())?;Ok(())}

It’s much nicer!

Ending the expression with? will result in theOk’s unwrapped value, unless the resultisErr, in which caseErr is returned early from the enclosing function.

? can be used in functions that returnResult because of theearly return ofErr that it provides.

§Representation

In some cases,Result<T, E> comes with size, alignment, and ABIguarantees. Specifically, one of either theT orE type must be a typethat qualifies for theOptionrepresentation guarantees (let’scall that typeI), and theother type is a zero-sized type withalignment 1 (a “1-ZST”).

If that is the case, thenResult<T, E> has the same size, alignment, andfunction call ABI asI (and therefore, asOption<I>). IfI isT,it is therefore sound to transmute a valuet of typeI to typeResult<T, E> (producing the valueOk(t)) and to transmute a valueOk(t) of typeResult<T, E> to typeI (producing the valuet). IfIisE, the same applies withOk replaced byErr.

For example,NonZeroI32 qualifies for theOption representationguarantees and() is a zero-sized type with alignment 1. This means thatbothResult<NonZeroI32, ()> andResult<(), NonZeroI32> have the samesize, alignment, and ABI asNonZeroI32 (andOption<NonZeroI32>). Theonly difference between these is in the implied semantics:

  • Option<NonZeroI32> is “a non-zero i32 might be present”
  • Result<NonZeroI32, ()> is “a non-zero i32 success result, if any”
  • Result<(), NonZeroI32> is “a non-zero i32 error result, if any”

§Method overview

In addition to working with pattern matching,Result provides awide variety of different methods.

§Querying the variant

Theis_ok andis_err methods returntrue if theResultisOk orErr, respectively.

Theis_ok_and andis_err_and methods apply the provided functionto the contents of theResult to produce a boolean value. If theResult does not have the expected variantthenfalse is returned instead without executing the function.

§Adapters for working with references

  • as_ref converts from&Result<T, E> toResult<&T, &E>
  • as_mut converts from&mut Result<T, E> toResult<&mut T, &mut E>
  • as_deref converts from&Result<T, E> toResult<&T::Target, &E>
  • as_deref_mut converts from&mut Result<T, E> toResult<&mut T::Target, &mut E>

§Extracting contained values

These methods extract the contained value in aResult<T, E> when itis theOk variant. If theResult isErr:

The panicking methodsexpect andunwrap requireE toimplement theDebug trait.

These methods extract the contained value in aResult<T, E> when itis theErr variant. They requireT to implement theDebugtrait. If theResult isOk:

§Transforming contained values

These methods transformResult toOption:

These methods transform the contained value of theOk variant:

  • map transformsResult<T, E> intoResult<U, E> by applyingthe provided function to the contained value ofOk and leavingErr values unchanged
  • inspect takes ownership of theResult, applies theprovided function to the contained value by reference,and then returns theResult

These methods transform the contained value of theErr variant:

These methods transform aResult<T, E> into a value of a possiblydifferent typeU:

  • map_or applies the provided function to the contained value ofOk, or returns the provided default value if theResult isErr
  • map_or_else applies the provided function to the contained valueofOk, or applies the provided default fallback function to thecontained value ofErr

§Boolean operators

These methods treat theResult as a boolean value, whereOkacts liketrue andErr acts likefalse. There are twocategories of these methods: ones that take aResult as input, andones that take a function as input (to be lazily evaluated).

Theand andor methods take anotherResult as input, andproduce aResult as output. Theand method can produce aResult<U, E> value having a different inner typeU thanResult<T, E>. Theor method can produce aResult<T, F>value having a different error typeF thanResult<T, E>.

methodselfinputoutput
andErr(e)(ignored)Err(e)
andOk(x)Err(d)Err(d)
andOk(x)Ok(y)Ok(y)
orErr(e)Err(d)Err(d)
orErr(e)Ok(y)Ok(y)
orOk(x)(ignored)Ok(x)

Theand_then andor_else methods take a function as input, andonly evaluate the function when they need to produce a new value. Theand_then method can produce aResult<U, E> value having adifferent inner typeU thanResult<T, E>. Theor_else methodcan produce aResult<T, F> value having a different error typeFthanResult<T, E>.

methodselffunction inputfunction resultoutput
and_thenErr(e)(not provided)(not evaluated)Err(e)
and_thenOk(x)xErr(d)Err(d)
and_thenOk(x)xOk(y)Ok(y)
or_elseErr(e)eErr(d)Err(d)
or_elseErr(e)eOk(y)Ok(y)
or_elseOk(x)(not provided)(not evaluated)Ok(x)

§Comparison operators

IfT andE both implementPartialOrd thenResult<T, E> willderive itsPartialOrd implementation. With this order, anOkcompares as less than anyErr, while twoOk or twoErrcompare as their contained values would inT orE respectively. IfTandE both also implementOrd, then so doesResult<T, E>.

assert!(Ok(1) <Err(0));letx:Result<i32, ()> =Ok(0);lety =Ok(1);assert!(x < y);letx:Result<(), i32> =Err(0);lety =Err(1);assert!(x < y);

§Iterating overResult

AResult can be iterated over. This can be helpful if you need aniterator that is conditionally empty. The iterator will either producea single value (when theResult isOk), or produce no values(when theResult isErr). For example,into_iter acts likeonce(v) if theResult isOk(v), and likeempty() if theResult isErr.

Iterators overResult<T, E> come in three types:

  • into_iter consumes theResult and produces the containedvalue
  • iter produces an immutable reference of type&T to thecontained value
  • iter_mut produces a mutable reference of type&mut T to thecontained value

SeeIterating overOption for examples of how this can be useful.

You might want to use an iterator chain to do multiple instances of anoperation that can fail, but would like to ignore failures whilecontinuing to process the successful results. In this example, we takeadvantage of the iterable nature ofResult to select only theOk values usingflatten.

letmutresults =vec![];letmuterrs =vec![];letnums: Vec<_> = ["17","not a number","99","-27","768"]   .into_iter()   .map(u8::from_str)// Save clones of the raw `Result` values to inspect.inspect(|x| results.push(x.clone()))// Challenge: explain how this captures only the `Err` values.inspect(|x| errs.extend(x.clone().err()))   .flatten()   .collect();assert_eq!(errs.len(),3);assert_eq!(nums, [17,99]);println!("results {results:?}");println!("errs {errs:?}");println!("nums {nums:?}");

§Collecting intoResult

Result implements theFromIterator trait,which allows an iterator overResult values to be collected into aResult of a collection of each contained value of the originalResult values, orErr if any of the elements wasErr.

letv = [Ok(2),Ok(4),Err("err!"),Ok(8)];letres:Result<Vec<_>,&str> = v.into_iter().collect();assert_eq!(res,Err("err!"));letv = [Ok(2),Ok(4),Ok(8)];letres:Result<Vec<_>,&str> = v.into_iter().collect();assert_eq!(res,Ok(vec![2,4,8]));

Result also implements theProduct andSum traits, allowing an iterator overResult valuesto provide theproduct andsum methods.

letv = [Err("error!"),Ok(1),Ok(2),Ok(3),Err("foo")];letres:Result<i32,&str> = v.into_iter().sum();assert_eq!(res,Err("error!"));letv = [Ok(1),Ok(2),Ok(21)];letres:Result<i32,&str> = v.into_iter().product();assert_eq!(res,Ok(42));

Structs§

IntoIter
An iterator over the value in aOk variant of aResult.
Iter
An iterator over a reference to theOk variant of aResult.
IterMut
An iterator over a mutable reference to theOk variant of aResult.

Enums§

Result
Result is a type that represents either success (Ok) or failure (Err).

[8]ページ先頭

©2009-2026 Movatter.jp