Why is it that there is anOption.expect(M)
, but noResult.expect(M)
?
I opened a pull request [pr] which put this in, and it turns out the reason there is no expect
function is because you are intended to use composition:
This method is unnecessary with the option adapters - res.ok().expect() does exactly what this method would do.
So you write the following Rust to expect success:
let my_value = this_might_fail().ok().expect("It failed :(");
And this to expect failure:
let my_value = this_might_succeed().err().expect("It succeeded :(");
If Result contains anErr(M)
, why is there no method which ensures you have anOk(T)
and fails otherwise?
Imagine I have some code which calls out to an external library, and returns a handle on success or an error string on failure. Now I want to retrieve this handle, and fail out if we were not able to get it. Upon failure, I want the reason for failure to be known so we can see what went wrong. Here are our requirements:
-
A simple call that performs the necessary matching, unboxing and failure.
-
A useful error message on failure.
Here is some Rust code that embodies that use case:
let main_window = sdl::Window::create( ... ).unwrap(); // (1)
main_window.be_awesome();
-
This will fail if the window could not be created, however we will get a generic error message. Even though
create
gives us a specific error message as to 'why' creation failed, this isn’t reported at task failure.
unwrap
[std] checks that the result is Ok
and errors otherwise; this is what I want, but it throws a generic error message instead of the value of Err
. This has the syntax we want, but doesn’t fulfill the second requirement.
According to the pull request [pr] from earlier, this functionality actually does belong in the unwrap
function:
The expect method has previously not existed on the Result type because you have an obvious error message (the Err value). In the past the error value had the ToStr bound so a good message could be presented as part of unwrap, but that seems to have gone away.
Fortunately, Rust is an awesome language and we can implement our own way of doing this 'without altering the standard library.'
First we need to define the trait, which specifies our own version of unwrap
. Since there are plans to change unwrap
to get
in the future, we will modify the future API in our example.
trait GetWithFailMessaged<T> {
fn getM(self) -> T;
}
We have made a 'generic trait', which means this definition can be applied to 'anything which returns an object of a specific type to be determined later.' Next, we need to make an 'implementation' of our trait for the Result types:
impl<T,E:Any+Send> GetWithFailMessaged<T> for Result<T,E> {
fn getM(self) -> T {
match self {
Ok(a) => a,
Err(b) => fail!(b)
}
}
}
What we have done is specify the 'implementation', which applies to any Result
as long as the error object is Send
-able. Since we are interested in strings as errors, and strings are Send
-able, then any result which takes a string in the Err
field is applicable. Now we can simply use getM
:
let x = this_might_fail().getM();
Which performs the same action as unwrap
[std], but throws the error stored within the Result instead of a generic one.
-
[std] 'Enum std::result::Result'. http://static.rust-lang.org/doc/master/std/result/enum.Result.html
-
[pr] 'Add Result::expect() for consistency with Option::expect().' rust-lang/rust#11140