In this lesson we'll explore how to unwrap a Result
type using a language feature called Pattern Matching.
Several questions here:
match
, you're using the fat arrow =>
for the Ok
and Err
code blocks, which presumably is doing something that is not immediately clear to me. Previously all we saw was the thin arrow ->
, which is still used here in the sum
function definition, and which seems to be indicating the function's return type. What is the difference between and the meaning behind the two arrow types?(I've worked a little with CoffeeScript, and I recall that it too uses both fat and thin arrows, which function similarly but bind different things to this
, while ES6 JavaScript has only the fat arrow, which also handles this
binding in place of an explicit bind
call, but I get the feeling the purpose of the arrows is different here.)
Speaking of that match
syntax, what exactly is going on in there? It looks like the outermost braces are wrapping a code block, but then inside it looks like an object, with Ok
and Err
properties that are lambdas. Or something. To be clear, I get that the value returned by parse
is triggering (and being passed to) one of the two functions inside the block; it's just that the way all of that is written looks a little unusual. It does remind me strongly of the switch
statement in JavaScript; is the structure and concept comparable?
Speaking of parse
, I noticed that now that we've pulled it out of the variable definition that previously supplied the intended type, and we're not using the turbofish syntax instead, so I would expect type inference to fail. Yet the code still compiles without issue. I also noticed that if I comment out a = val;
, then I get the expected type inference failure. Am I correct then that the compiler infers the type via the assignment that occurs inside the Ok
function? That's pretty crazy, and impressive.
I noticed that when I run the code, I get two warnings about the read_line
lines "not being used," but you only get one such warning in the video. Studying the video and the embedded code below it more closely, I discovered that when you're reading in first
in the video, you then chain unwrap
at the end, but not so when reading in second
, which is what throws your one warning. And in the embedded code, both read_line
instances chain unwrap
. And, sure enough, if I do the same, the warnings disappear. I don't recall you saying anything about adding unwrap
to either of those lines, though; was that just a quick-and-dirty way to get rid of the warnings, or is something more going on there?
Hi Matt,
->
is used to annotate the return type of a function/method. The fat arrow is just the syntax for match
branches. So doing:match some_expr {
Ok(val) => {
...
},
Err(e) => {
...
}
}
Really just indicates the body of the match branch. That also why, in case of single-line branch body's, they can be omitted:
match some_expr {
Ok(val) => ...
Err(e) => ...
};
Notice however that, when a match branch is only a single-line expression, the value of that expression will be the returned value from that match
expression.
It does remind me strongly of the switch statement in JavaScript; is the structure and concept comparable? Yes! Very correct. You can think of
match
pattern asswitch
statements on steroids. Match pattern are way more powerful though, because they support a variety of pattern syntaxes that let you express with a lot of fine-control what branch should match. I'll create a collection for pattern matching in the near future to dive more into that!
I'm not entirely sure I follow the question on type inference here. If you look at the code we and up with
let mut a:u32 = 0;
match first.trim().parse() {
Ok(val) => a = val,
Err(_err) => {
println!("Not a valid number!");
}
};
Putting parse()
into a match
expression doesn't change the fact that the function is generic and therefore need to be explicitly annotated. However, since we have an annotation on a: u32
and b: u32
, and we're assigning val
to both a
and b
respectively, Rust is smart enough to see that we're aiming to parse to u32
. Does that make sense?
I don't recall you saying anything about adding unwrap to either of those lines, though; was that just a quick-and-dirty way to get rid of the warnings, or is something more going on there?
Yea so that was a little mistake on my side. unwrap()
was covered in a previous lesson, and for the sake of the lesson I've only updated it in one place (but should've happened in both places). So the right thing to do (for completeness-sake) would be to apply the unwrap()
on both read_line()
calls.
Cool, thanks for all that!
- I'm not entirely sure I follow the question on type inference here. If you look at the code we and up with...
I think you answered what I was trying to ask.
- So the right thing to do (for completeness-sake) would be to apply the
unwrap()
on bothread_line()
calls.
I'm still a little confused on this, only because you introduced expect
as a better solution than unwrap
, and then match
as a better solution than expect
, so it was surprising to see unwrap
still present. And it's chained onto the read_line
calls where it's not clear that it's doing anything. So I was just curious if you only added it so that you wouldn't get the warning about those read_line
calls being "unused."
Hey Matt,
I'm still a little confused on this, only because you introduced expect as a better solution than unwrap, and then match as a better solution than expect, so it was surprising to see unwrap still present.
Very fair point. I wasn't clear about that at all.
So yes, the read_line()
call in itself returns a Result<T, E>
as well, however, we're not actually interested in that. In this case, we're only interested in it to mutate our String
buffer. So in order to satisfy the compiler, we unwrap()
the Result
returned from read_line()
and ignore what it returns (it'll still mutate the buffer though).
Hope this makes sense!