Question mark operator

pull/1/head
Dhghomon 4 years ago committed by GitHub
parent 3a62e33858
commit de2764f528
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -2338,7 +2338,89 @@ fn main() {
}
```
# The ? operator
There is an even shorter way to deal with Result (and Option), shorter than ```match``` and even shorter than ```if let```. It is called the "question mark operator", and is just ```?```. After a function that returns a result, you can add ```?```. This will:
* return the result if it is Ok
* pass the error back if it is Err
In other words, it does almost everything for you.
We can try this with ```.parse()``` again. We will write a function called ```parse_str``` that tries to turn a ```&str``` into a ```i32```. It looks like this:
```rust
fn parse_str(input: &str) -> Result<i32, std::num::ParseIntError> {
let parsed_number = input.parse::<i32>()?; // Here is the question mark
Ok(parsed_number)
}
```
This function takes a ```&str```. If it is Ok, it gives an ```i32``` wrapped in ```Ok```. If it is an Err, it returns a std::num::ParseIntError. Then we try to parse the number, and add ```?```. That means "check if it is an error, and give the result if it is okay". If it is not okay, it will return the error and end. But if it is okay, it will go to the next line. On the next line is the number inside of ```Ok()```. We need to wrap it in Ok because the return is ```Result<i32, std::num::ParseIntError>```, not ```i32```.
Now, we can try out our function. Let's see what it does with a vec of ```&str```s.
```rust
fn main() {
let str_vec = vec!["Seven", "8", "9.0", "nice", "6060"];
for item in str_vec {
let parsed = parse_str(item);
println!("{:?}", parsed);
}
}
fn parse_str(input: &str) -> Result<i32, std::num::ParseIntError> {
let parsed_number = input.parse::<i32>()?;
Ok(parsed_number)
}
```
This prints:
```
Err(ParseIntError { kind: InvalidDigit })
Ok(8)
Err(ParseIntError { kind: InvalidDigit })
Err(ParseIntError { kind: InvalidDigit })
Ok(6060)
```
How did we find std::num::ParseIntError? One easy way is to "ask" the compiler again.
```rust
fn main() {
let failure = "Not a number".parse::<i32>();
failure.rbrbrb(); // Compiler: "What is rbrbrb()???"
}
```
The compiler doesn't understand, and says:
```
error[E0599]: no method named `rbrbrb` found for enum `std::result::Result<i32, std::num::ParseIntError>` in the current scope
--> src\main.rs:3:13
|
3 | failure.rbrbrb();
| ^^^^^^ method not found in `std::result::Result<i32, std::num::ParseIntError>`
```
So ```std::result::Result<i32, std::num::ParseIntError>``` is the signature we need.
We don't need to write ```std::result::Result``` because ```Result``` is always "in scope" (in scope = ready to use). But std::num::ParseIntError is not in scope. We can bring it in scope if we want:
```use std::num::ParseIntError;```
Then we can write:
```rust
use std::num::ParseIntError;
fn parse_str(input: &str) -> Result<i32, ParseIntError> {
let parsed_number = input.parse::<i32>()?;
Ok(parsed_number)
}
```
# Traits

Loading…
Cancel
Save