Option & Result
Option
Option is concept from OCaml language. And it's used for some action can have no result or some result. As Rust don't have null, we can use None of Option
Option is looks like
enum Option<T> {
None,
Some(T)
}
It means, if there is no result, it's None. If there is some result of type T, it's Some(T).
We can imagine a situation that we want to get 5th value of a Vector.
fn take_fifth(value: Vec<i32>) -> Option<i32> {
if value.len() < 5 {
None // Option::None
} else {
Some(value[4]) // Some(i32)
}
}
fn main() {
let vec = vec![1, 2];
let fifth = take_fifth(vec);
println!("{:?}", fifth); // None
let vec = vec![1, 2, 3, 4, 5, 6];
let fifth = take_fifth(vec);
println!("{:?}", fifth); // Some(5)
}
take_fifth function check the length of Vector is less than 5 and if it is, returns None. If not, return Some(value[4]) that means fifth value of the Vector. The result is like the comment right after println statement.
Now, we got None or Some(5). But as we can see, 5 is wrapped in Option::Some.
So if you want to treat 5 as an i32 value, we have to unwrap it.
fn take_fifth(value: Vec<i32>) -> Option<i32> {
if value.len() < 5 {
None // Option::None
} else {
Some(value[4]) // Some(i32)
}
}
fn main() {
let vec = vec![1, 2];
let fifth = take_fifth(vec);
println!("{:?}", fifth); // None
let vec = vec![1, 2, 3, 4, 5, 6];
let fifth = take_fifth(vec);
println!("{:?}", fifth); // Some(5)
let i32_fifth = fifth.unwrap();
println!("{}", i32_fifth);
}
We can use .unwrap() method to unwrap and pull out the real value. But, we can imagine what if we unwrap None. If you try to unwrap None, you can see a panic thread 'main' panicked at 'called 'Option::unwrap()' on a 'None' value'.
This means as None doesn't have value, you cannot unwrap None.
So how could we check if an Option is None or Some? We can use match statement or .is_some(), .is_none() or .expect()
First, we can use match statement.
fn take_fifth(value: Vec<i32>) -> Option<i32> {
if value.len() < 5 {
None // Option::None
} else {
Some(value[4]) // Some(i32)
}
}
fn main() {
let vec = vec![1, 2];
let fifth = take_fifth(vec);
println!("{:?}", fifth); // None
match fifth {
Some(number) => println!("I got {}", number),
None => println!("None..")
} // None..
let vec = vec![1, 2, 3, 4, 5, 6];
let fifth = take_fifth(vec);
println!("{:?}", fifth); // Some(5)
match fifth {
Some(number) => println!("I got {}", number),
None => println!("None..")
} // I got 5
}
As we can see, we used match fifth{}. We can check if fifth is Some(number) or None and printed the number or "None..". So we can check and printed right result using match statement.
Second, we can check if Option is None or Some(T) by .is_none() or .is_some().
fn take_fifth(value: Vec<i32>) -> Option<i32> {
if value.len() < 5 {
None // Option::None
} else {
Some(value[4]) // Some(i32)
}
}
fn main() {
let vec = vec![1, 2];
let fifth = take_fifth(vec);
println!("{:?}", fifth); // None
if fifth.is_none() {
println!("I got Nothing");
} // I got Nothing
let vec = vec![1, 2, 3, 4, 5, 6];
let fifth = take_fifth(vec);
println!("{:?}", fifth); // Some(5)
if fifth.is_some() {
println!("I got {}", fifth.unwrap());
} // I got 5
}
Code above, we used .is_none() and .is_some() to check if its None or Some. We can know the meaning of the code intuitively.
At last, we can use .expect() to deal with None and Some.
fn take_fifth(value: Vec<i32>) -> Option<i32> {
if value.len() < 5 {
None // Option::None
} else {
Some(value[4]) // Some(i32)
}
}
fn main() {
let vec = vec![1, 2];
let fifth = take_fifth(vec);
println!("{:?}", fifth); // None
// println!("We expect: {}", fifth.expect("Needed at least five items - make sure Vec has at least 5 items"));
// panic occur
let vec = vec![1, 2, 3, 4, 5, 6];
let fifth = take_fifth(vec);
println!("{:?}", fifth); // Some(5)
println!("We expect: {}", fifth.expect("Needed at least five items - make sure Vec has at least 5 items"));
// We expect: 5
}
Code above, we used fifth.expect("~~~"). And ~~~ is the panic message if there is a panic. If we use .expect, Rust check if our Option is Some and if its None, make a panic with the message we gave. And if its Some, .expect returns the value inside.
Like I wrote above, we've made Option, check and unwrapped Option with various ways. We can use Option for showing null in Rust.
Result
As Option is maybe there, maybe not, Result is it can work or not.
Result is looks like
enum Result<T, E> {
Ok(T),
Err(E)
}
T is generics for result, and E is generics for errors. So if some action can executed, it will have Ok, but if it cannot executed, it will have Err.
Let's see a simple example. We can imagine if we want to get error if input is odd, and get ok if input is even.
fn check_even(input: i32) -> Result<(), ()> {
if input % 2 == 0 {
Ok(())
} else {
Err(())
}
}
fn main() {
match check_even(34) {
Ok(_) => println!("Okay!!"),
Err(_) => println!("Error!!");
}
// Okay!!
}
Everything is almost same as Option. But, Result gets two generics. The first () is for Ok, and second () is for Err(() is unit type that means nothing). So Ok and Err don't have any value.
And as we wrote like Some(number) => println!("I got {}", number), at the match statement of Option, we can use like Ok(x) => ~~ in match statement.
Same as Option, the result of Result is wrapped in Result type. So if you want to get original value of Result, we have to use .unwrap() here too. But as we met Panic when we unwrapped None, we'll meet Panic if we unwrap Err. We have to check if its Err or Ok.
We can use match statement, .is_ok(), .is_err(), or .expect() as what we did at Option. I'll omit the examples cause they'll almost same as Option's examples.
So you can choose between Option and Result by situation. And the usage is almost the same. Option is for no result or result, Result is for error or normal result.
Author And Source
이 문제에 관하여(Option & Result), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@eslerkang/Rust-Option-Result저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념
(Collection and Share based on the CC Protocol.)