上QQ阅读APP看书,第一时间看更新
How to do it...
Follow these steps to explore enums:
- Create a new project with cargo new enums --lib and open this folder in Visual Studio Code, or any IDE of your choosing.
- Open src/lib.rs and declare an enum containing some data:
use std::io;
pub enum ApplicationError {
Code { full: usize, short: u16 },
Message(String),
IOWrapper(io::Error),
Unknown
}
- In addition to the declaration, we also implement a simple function:
impl ApplicationError {
pub fn print_kind(&self, mut to: &mut impl io::Write) ->
io::Result<()> {
let kind = match self {
ApplicationError::Code { full: _, short: _ } => "Code",
ApplicationError::Unknown => "Unknown",
ApplicationError::IOWrapper(_) => "IOWrapper",
ApplicationError::Message(_) => "Message"
};
write!(&mut to, "{}", kind)?;
Ok(())
}
}
- Now, we also need to do something with the enum, so let's implement a dummy function called do_work:
pub fn do_work(choice: i32) -> Result<(), ApplicationError> {
if choice < -100 {
Err(ApplicationError::IOWrapper(io::Error::
from(io::ErrorKind::Other
)))
} else if choice == 42 {
Err(ApplicationError::Code { full: choice as usize, short:
(choice % u16::max_value() as i32) as u16 } )
} else if choice > 42 {
Err(ApplicationError::Message(
format!("{} lead to a terrible error", choice)
))
} else {
Err(ApplicationError::Unknown)
}
}
- Nothing is true until it's tested! Now, add a number of tests that show the powerful matching of enums, starting with the do_work() function:
#[cfg(test)]
mod tests {
use super::{ApplicationError, do_work};
use std::io;
#[test]
fn test_do_work() {
let choice = 10;
if let Err(error) = do_work(choice) {
match error {
ApplicationError::Code { full: code, short: _ } =>
assert_eq!(choice as usize, code),
// the following arm matches both variants (OR)
ApplicationError::Unknown |
ApplicationError::IOWrapper(_) => assert!(choice <
42),
ApplicationError::Message(msg) =>
assert_eq!(format!
("{} lead to a terrible error", choice), msg)
}
}
}
For the get_kind() function, we also require a test:
#[test]
fn test_application_error_get_kind() {
let mut target = vec![];
let _ = ApplicationError::Code { full: 100, short: 100
}.print_kind(&mut target);
assert_eq!(String::from_utf8(target).unwrap(),
"Code".to_string());
let mut target = vec![];
let _ = ApplicationError::Message("0".to_string()).
print_kind(&mut target);
assert_eq!(String::from_utf8(target).unwrap(),
"Message".to_string());
let mut target = vec![];
let _ = ApplicationError::Unknown.print_kind(&mut target);
assert_eq!(String::from_utf8(target).unwrap(),
"Unknown".to_string());
let mut target = vec![];
let error = io::Error::from(io::ErrorKind::WriteZero);
let _ = ApplicationError::IOWrapper(error).print_kind(&mut
target);
assert_eq!(String::from_utf8(target).unwrap(),
"IOWrapper".to_string());
}
}
- In a call to cargo test in the root directory of the project, we can observe the output:
$ cargo test
Compiling enums v0.1.0 (Rust-Cookbook/Chapter02/enums)
Finished dev [unoptimized + debuginfo] target(s) in 0.61s
Running target/debug/deps/enums-af52cbd5cd8d54cb
running 2 tests
test tests::test_do_work ... ok
test tests::test_application_error_get_kind ... ok
test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out
Doc-tests enums
running 0 tests
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out
Now, let's see how enums work under the hood.