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.)