RU beehive logo promo banner for Computing & Info Sciences
CS 320
2025spring
ibarland

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”.)

  1. Create a new project, say “array-passing”.
    cargo init array-passing
    . Make sure you can cargo test it.
  2. 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].
  3. 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, … ]);
  4. 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.
  5. 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.

  6. Write a stub version of triple_each. Now you should be able to run the test, but it should fail that test.
  7. 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.
  8. Instructor's note: we made it here, in 1h15m.
  9. 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:

    1. 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 already1 on your computer.
    2. 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!.

  10. 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.
  11. 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.

  12. 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!

1 More precisely: The initial-fetch of the library will grab the most recent version, but it won't re-check for updates in the future.      

logo for creative commons by-attribution license
This page licensed CC-BY 4.0 Ian Barland
Page last generated
Please mail any suggestions
(incl. typos, broken links)
to ibarlandradford.edu
Rendered by Racket.