Rust Programming Cookbook
上QQ阅读APP看书,第一时间看更新

How to do it...

Since we are exploring a built-in library feature, we'll create several tests that cover everything:

  1. Create a new project using cargo new not-null --lib and open the project folder using Visual Studio code. 
  2. 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");
}
  1. 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)
}
}
  1. 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);
}
  1. 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);
}
}
  1. 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.