上QQ阅读APP看书,第一时间看更新
How to do it...
Since we are exploring a built-in library feature, we'll create several tests that cover everything:
- Create a new project using cargo new not-null --lib and open the project folder using Visual Studio code.
- To start off, let's see what unwrap() does and replace the default test in src/lib.rs with the following code:
#[test]
#[should_panic]
fn option_unwrap() {
// Options to unwrap Options
assert_eq!(Some(10).unwrap(), 10);
assert_eq!(None.unwrap_or(10), 10);
assert_eq!(None.unwrap_or_else(|| 5 * 2), 10);
Option::<i32>::None.unwrap();
Option::<i32>::None.expect("Better say something when
panicking");
}
- Option also wraps values well, and it's sometimes complicated (or simply verbose) to get them out. Here are a number of ways of getting the value out:
#[test]
fn option_working_with_values() {
let mut o = Some(42);
let nr = o.take();
assert!(o.is_none());
assert_eq!(nr, Some(42));
let mut o = Some(42);
assert_eq!(o.replace(1535), Some(42));
assert_eq!(o, Some(1535));
let o = Some(1535);
assert_eq!(o.map(|v| format!("{:#x}", v)),
Some("0x5ff".to_owned()));
let o = Some(1535);
match o.ok_or("Nope") {
Ok(nr) => assert_eq!(nr, 1535),
Err(_) => assert!(false)
}
}
- Due to their functional origins, where it's often not important whether one works on a single value or a collection, Option also behaves like a collection in some ways:
#[test]
fn option_sequentials() {
let a = Some(42);
let b = Some(1535);
// boolean logic with options. Note the returned values
assert_eq!(a.and(b), Some(1535));
assert_eq!(a.and(Option::<i32>::None), None);
assert_eq!(a.or(None), Some(42));
assert_eq!(a.or(b), Some(42));
assert_eq!(None.or(a), Some(42));
let new_a = a.and_then(|v| Some(v + 100))
.filter(|&v| v != 42);
assert_eq!(new_a, Some(142));
let mut a_iter = new_a.iter();
assert_eq!(a_iter.next(), Some(&142));
assert_eq!(a_iter.next(), None);
}
- Lastly, using the match clause on Option is very popular and often necessary:
#[test]
fn option_pattern_matching() {
// Some trivial pattern matching since this is common
match Some(100) {
Some(v) => assert_eq!(v, 100),
None => assert!(false)
};
if let Some(v) = Some(42) {
assert_eq!(v, 42);
}
else {
assert!(false);
}
}
- To see it all working, we should also run cargo test:
$ cargo test
Compiling not-null v0.1.0 (Rust-Cookbook/Chapter02/not-null)
Finished dev [unoptimized + debuginfo] target(s) in 0.58s
Running target/debug/deps/not_null-ed3a746487e7e3fc
running 4 tests
test tests::option_pattern_matching ... ok
test tests::option_sequentials ... ok
test tests::option_unwrap ... ok
test tests::option_working_with_values ... ok
test result: ok. 4 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out
Doc-tests not-null
running 0 tests
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out
Now, let's go behind the scenes to understand the code better.