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

How to do it...

Let's use Rust's unit tests as a playground for some data type experiments:

  1. Create a new project using cargo new data-types -- lib and use an editor to open the projects directory.
  2. Open src/lib.rs in your favorite text editor (Visual Studio Code).
  3. In there, you will find a small snippet to run a test:
#[cfg(test)]
mod tests {
#[test]
fn it_works() {
assert_eq!(2 + 2, 4);
}
}
  1. Let's replace the default test to play with various standard data types. This test uses a few ways to work with data types and their math functions, as well as mutability and overflows:
    #[test]
fn basic_math_stuff() {
assert_eq!(2 + 2, 4);

assert_eq!(3.14 + 22.86, 26_f32);

assert_eq!(2_i32.pow(2), 4);
assert_eq!(4_f32.sqrt(), 2_f32);

let a: u64 = 32;
let b: u64 = 64;

// Risky, this could overflow
assert_eq!(b - a, 32);
assert_eq!(a.overflowing_sub(b), (18446744073709551584,
true));
let mut c = 100;
c += 1;
assert_eq!(c, 101);
}
  1. Having the basic numeric types covered, let's check a major limitation: overflows! Rust panics when an overflow occurs, so we are going to expect that with the #[should_panic] attribute (the test will actually fail if it doesn't panic):
    #[test]
#[should_panic]
fn attempt_overflows() {
let a = 10_u32;
let b = 11_u32;

// This will panic since the result is going to be an
// unsigned type which cannot handle negative numbers
// Note: _ means ignore the result
let _ = a - b;
}
  1. Next, let's create a custom type as well. Rust's types are structs and they add no overhead in memory. The type features a new() (constructor by convention) and a sum() function, both of which we'll call in a test function:

// Rust allows another macro type: derive. It allows to "auto-implement"
// supported traits. Clone, Debug, Copy are typically handy to derive.
#[derive(Clone, Debug, Copy)]
struct MyCustomStruct {
a: i32,
b: u32,
pub c: f32
}

// A typical Rust struct has an impl block for behavior
impl MyCustomStruct {

// The new function is static function, and by convention a
// constructor
pub fn new(a: i32, b: u32, c: f32) -> MyCustomStruct {
MyCustomStruct {
a: a, b: b, c: c
}
}

// Instance functions feature a "self" reference as the first
// parameter
// This self reference can be mutable or owned, just like other
// variables
pub fn sum(&self) -> f32 {
self.a as f32 + self.b as f32 + self.c
}
}
  1. To see the new struct function in action, let's add a test to do some and clone memory tricks with types (note: pay attention to the asserts):
    use super::MyCustomStruct;

#[test]
fn test_custom_struct() {
assert_eq!(mem::size_of::<MyCustomStruct>(),
mem::size_of::<i32>() + mem::size_of::<u32>() +
mem::size_of::<f32>());

let m = MyCustomStruct::new(1, 2, 3_f32);
assert_eq!(m.a, 1);
assert_eq!(m.b, 2);
assert_eq!(m.c, 3_f32);

assert_eq!(m.sum(), 6_f32);
let m2 = m.clone();
assert_eq!(format!("{:?}", m2), "MyCustomStruct { a: 1, b:
2,
c: 3.0 }");

let mut m3 = m;
m3.a = 100;

assert_eq!(m2.a, 1);
assert_eq!(m.a, 1);
assert_eq!(m3.a, 100);
}
  1. Lastly, let's see whether all of that works. Run cargo test in the data-types directory and you should see the following output:
$ cargo test
Compiling data-types v0.1.0 (Rust-Cookbook/Chapter01/data-types)
warning: method is never used: `new`
--> src/lib.rs:13:5
|
13 | pub fn new(a: i32, b: u32, c: f32) -> MyCustomStruct {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: #[warn(dead_code)] on by default

warning: method is never used: `sum`
--> src/lib.rs:19:5
|
19 | pub fn sum(&self) -> f32 {
| ^^^^^^^^^^^^^^^^^^^^^^^^

Finished dev [unoptimized + debuginfo] target(s) in 0.50s
Running target/debug/deps/data_types-33e3290928407ff5

running 3 tests
test tests::basic_math_stuff ... ok
test tests::attempt_overflows ... ok
test tests::test_custom_struct ... ok

test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out

Doc-tests data-types

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.