Part 3. Reversing a vector (15 points)
In the rest of the lab, you’re going to write some short functions dealing with vectors and strings and you’re going to write some unit tests for the functions.
Continue working in the main.rs
file of your iteration
project.
Your task
Implement the function reversed_vec
.
fn reversed_vec(input_data: &[i32]) -> Vec<i32> {
let mut result: Vec<i32> = Vec::new();
todo!("Finish this function")
}
Two things to notice
- The input argument
input_data
is of type&[i32]
. We’ll talk more about this type later, but for now, think of this as a reference to aVec
. We saw this above when we wrotefor x in &data {}
wheredata
was aVec
so&data
essentially gives us a&[i32]
. - The
result
variable is declared mutable (with themut
keyword) so we can modify it by inserting elements using thepush()
function.
Before you remove the todo!()
and implement this function, let’s write a
unit test similar to the unit tests you wrote in CSCI 151.
At the bottom of main.rs
, add the following code.
#[cfg(test)]
mod test {
use super::*;
#[test]
fn reversed_vec_empty() {
let data = vec![];
assert_eq!(reversed_vec(&data), vec![]);
}
}
There’s a lot to unpack here. The first line, #[cfg(test)]
tells the
compiler that the item that follows it should only be compiled when we’re
compiling tests. And that item is a module named test
. (The name is
arbitrary but is traditionally called test
.) We’ll talk more about modules
later.
The use super::*;
line makes all of the functions in main.rs
outside the
test
module available for use inside the test
module.
Finally, each unit test we write is just a Rust function that is annotated
with #[test]
. If you omit this annotation, the function will not be treated
as a test.
Run the command $ cargo test
. You should see some warnings followed by a
test failure (remember, we didn’t implement reversed_vec()
so it makes sense
our test should fail).
running 1 test
test test::reversed_vec_empty ... FAILED
failures:
---- test::reversed_vec_empty stdout ----
thread 'test::reversed_vec_empty' panicked at 'not yet implemented: Finish this function', src/main.rs:19:5
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
failures:
test::reversed_vec_empty
test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
Notice that the output tells us our code panicked (i.e., failed) on line 19 of
main.rs
.
Before implementing reversed_vec()
, write two more tests
#[test]
fn reversed_vec_one() {
todo!();
}
#[test]
fn reversed_vec_three() {
todo!();
}
that test the result of reversing a vector with 1 element and a vector with 3 elements.
$ cargo test
should now show three failing tests.
Implement the rest of reversed_vec()
.
- You can create an iterator over
input_data
usinginput_data.iter()
. Some iterators let you create reverse iterators using therev()
function. In other words, given one iteratorit
, you can create a new iterator viait.rev()
that will iterate in reverse order. Sofor x in input_data.iter().rev() { }
will iterate overinput_data
in reverse order. - The iterator returned by
input_data.iter()
will not make copies of the elements ininput_data
. Instead, the value returned by the iterator will be a reference to the elements. That is, in
the type offor x in input_data.iter() { }
x
is&i32
and noti32
. Since ourresult
vector holdsi32
and not&i32
, we need to dereference the referencex
to get the underlying integer. We use the*
operator to do this. For example,
shows the incorrect and correct ways to insert the element intofor x in input_data.iter() { // result.push(x); // Fails because x has type &i32 result.push(*x); // Succeeds because *x has type i32 }
result
.