home—lectures—recipe—hws—exams—D2L—zoom (snow day)
Passing arrays
We will write a method triple_each,
which takes in an array-slice of doubles (&[f64])
and triple every element of that array.
(It's a “void method”.)
- Create a new project, say “array-passing”.
cargo init array-passing
.
Make sure you can cargo test it.
- Write the signature for test_triple_each.
Leave the body empty, but make sure you can compile/run it.
fn test_triple_each() -> () {}
Be sure to annotate it as a #[test].
- Have the test-method declare a variable & initialize it to hold
an array of, say, exactly-five 5 f64s.
What is a good variety of numbers to have, in your array?
Also: Make sure that one of the values is 0.1.
Confirm that you can successfully cargo test.
let my_nums = [0.0, 1.0, …, 0.1, … ]);
- Now, make a unit-test for triple_each
(even though we haven't even written that function's signature yet!).
triple_each( &my_nums );
assert_eq!( my_nums, [0.0, 3.0, …, 0.3, … ]); |
It won't compile quite yet.
- Make some further tests, passing a small slice to triple_each.
We should test passing in array (slices)
slices of size 0 and size 1, as well as size-many.
Sneaky trick:
Rather than make three or four arrays of several sizes,
we'll must just one array my_nums,
but we can pass smaller slices of if to our function:
e.g. here's a test of a size-2 array
triple_each( &my_nums[1..3] );
assert_eq!( my_nums, [0.0, 9.0, …, 0.3, … ]); |
Now it's easy to test a couple of size-0 and size-1 slices.
(And it's still wise to assert_eq! that the other array-elements
are indeed unchanged.)
Careful:
When unit-testing void methods that mutate values,
the order of the tests matter;
tripling some array-elements with an early test
will change what our expected outputs will be in later tests.
In general, using mutation means we have to worry about things more closely.
- Write a stub version of triple_each.
Now you should be able to run the test, but it should fail that test.
- Finally, fill in the body of triple_each.
You'd expect it should pass the tests, and it nearly will,
but not quite: 3.0 * 0.1 is not 0.3!
Add the single test
assert_eq!(0.3, 0.1 * 3.0);
(before your other tests),
and confirm that that's the issue.
Instructor's note: we made it here, in 1h15m.
How to compare f64s properly in rust
We will compare doubles using assert_f64_near!
instead of assert_eq!;
this function allows some tolerance to accommodate floating-point error.
Sadly, this is a function not part of standard-rust;
instead it's in a crate (library) named assert_float_eq.
We want to import the function from the library into our code.
There are two steps to doing this:
- In your Cargo.toml, add a dependency: assert_float_eq = "*"
This line should come just after the line [dependencies] that's already in your Cargo.toml.
The "*" means to go fetch the most recent version of the library.
That fetch will happen next time we invoke cargo test,
if it's not already on your computer.
- At the top of your .rs file, add use assert_float_eq::assert_f64_near;
which is akin to Java's import.
As with Java, it is actually optional;
it just means to use the function you must use it's fully-qualified name,
use assert_float_eq::assert_f64_near!.
Using this library,
change your assert_eq!(0.3, 0.1 * 3.0);
to assert_f64_near!(0.3, 0.1 * 3.0)
and confirm that this, at least, now passes.
So how to test our array of f64s?
I guess we need to write five lines:
assert_f64_near!( my_nums[0], 0.0 );
assert_f64_near!( my_nums[1], 3.0 );
…
assert_f64_near!( my_nums[3], 0.3 );
… |
What a pain!
But wait:
We. Are. Programmers.
Do we need to put up with that boring copypasta code?
no!
Let's write our own loop to do this.
In fact, we can see that this will be a task to do repeatedly,
so we'll write
a function that accepts two array-slices
and calls
assert_f64_near!
on the corresponding elements.
// assert two arrays of f64 are (nearly) equal.
//
fn assert_f64s_near( a: &[f64], b: &[f64] ) -> () {
assert_eq!(a.len(), b.len());
for i = 0..a.len() {
assert_f64_near!(a[i], b[i]);
}
} |
Note that our function is named assert_f64s_near (plural),
and it does not end in “!”
because it's a regular function, not a macro.
Finally:
change assert_eq!( <some-array-of-f64s>, <some-other-array-of-f64s> )
to instead call our assert_f64s_near.
Your tests should now pass.
Huzzah!
home—lectures—recipe—hws—exams—D2L—zoom (snow day)
 This page licensed CC-BY 4.0 Ian Barland Page last generated | Please mail any suggestions (incl. typos, broken links) to ibarland radford.edu |
 |