Developers new to Rust probably have encountered the into and unwrap method calls several times in sample codes. At first sight, these calls may appear puzzling to them. So, where do we use these methods? Chances are these methods that are invoked from Option enums and structs that implement the Into (or From) trait.
Into Trait, Into Method
The Into trait is generally for data conversions. For instance, convert a struct instance into an object of a different struct definition. Consider the following sample codes.
main.rs
Rust
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#[derive(Debug)]
structPerson{
name:String
}
implInto<Employee>forPerson{
fninto(self)->Employee{
Employee{
name:self.name
}
}
}
#[derive(Debug)]
structEmployee{
name:String
}
fnmain(){
letperson:Person=Person{name:"Karl".to_string()};
letemployee:Employee=person.into();
println!("{:?}",employee);
}
Rust Option and Unwrap Method
When we deal with the enum Option, we use the
unwrap() method to get the value of the optional value. Consider the following codes.
main.rs
Rust
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// Get even numbers from a Vec instance
fnget_even_numbers(v:Vec<i32>)->Option<Vec<i32>>{
letmuttmp_v=Vec::new();
foriinv.into_iter(){
ifi%2==0{
tmp_v.push(i.clone());
}
}
iftmp_v.len()>0{
// Return Some that has even numbers
Some(tmp_v)
}else{
// Return None because there aren't any even numbers
None
}
}
// Main function
fnmain(){
letvec_option1=get_even_numbers(vec![1,2,4,5]);
println!("{:?}",vec_option1.unwrap());
letvec_option2=get_even_numbers(vec![1,3,5,7]);
println!("{:?}",vec_option2.unwrap());
}
The codes generate the following output.
1
2
3
4
5
[2,4]
thread'main'panicked at'called `Option::unwrap()` on a `None` value',src\main.rs:27:22
stack backtrace:
0:backtrace::backtrace::trace_unsynchronized
...
The panic is caused by the
unwrap() method when the Option has no value. To resolve this, we could use either of the following alternatives.
Some(#[stable(feature = "rust1", since = "1.0.0")] T),
}
...
#[inline]
#[track_caller]
#[stable(feature = "rust1", since = "1.0.0")]
pubfnunwrap(self)->T{
matchself{
Some(val)=>val,
None=>panic!("called `Option::unwrap()` on a `None` value"),
}
}
The
unwrap() method simply returns the Option value, if there is any. Otherwise, it returns panics for None. What if we want our Option enum that works the same way?
First, we need to create our enum type.
Rust
1
2
3
4
enumMyOption<T>{
HasSome(T),
HasNone,
}
Second, implement the Default trait for dealing with an empty value.
Rust
1
2
3
4
5
6
7
8
impl<T:Default>MyOption<T>{
pubfnunwrap(self)->T{
matchself{
MyOption::HasSome(x)=>x,
MyOption::HasNone=>Default::default(),
}
}
}
Third, modify the
get_even_numbers and use the new enum.