Non Empty Vector
In this exercise, you will implement a non-empty vector type. This type is a vector that is compile-time guaranteed to have at least one element. It can be useful when you want to ensure that a vector is never empty and avoid the overhead of checking for emptiness.
For example, a function can return a NonEmptyVec<T>
instead of a Vec<T>
to guarantee to its caller that the vector has at least one element. Or, a function can receive a NonEmptyVec<T>
as an argument to force the caller to guarantee that the vector has at least one element.
To Do
-
Implement the following methods for
NonEmptyVec
:new
: creates a newNonEmptyVec
with a single element.push
: pushes an element to the end of theNonEmptyVec
.get
: returns the element at the given index, if it exists.first
(last
): returns the first (last) element of theNonEmptyVec
. UnlikeVec::first
, this method should not return an Option!first_mut
(last_mut
): returns a mutable reference to the first (last) element of theNonEmptyVec
.pop
: removes the last element from theNonEmptyVec
and returns it, along with the remaining elements. UnlikeVec::pop
, this method should not return an Option (pop should succeed even if there is a single element).
Think carefully about the signature of these methods. For each input and output argument, consider whether it should be owned, borrowed, or mutably borrowed.
-
Fill in the missing parts in the unit tests below (We didn't write the full tests for you to avoid spoiling the signatures).
You can test your implementation by running
cargo test
.
#![allow(unused)] fn main() { pub struct NonEmptyVec<T> { head: T, tail: Vec<T>, } #[cfg(test)] mod tests { use super::*; #[test] fn test_new() { let x: NonEmptyVec<i32> = NonEmptyVec::new(5); todo!("assert that x.first() returns 5, and that x.last() also returns 5."); } #[test] fn test_push() { let mut x: NonEmptyVec<i32> = NonEmptyVec::new(5); x.push(10); todo!("assert that x.first() returns 5, and that x.last() returns 10."); } #[test] fn test_get() { let mut x: NonEmptyVec<i32> = NonEmptyVec::new(5); x.push(10); x.push(15); todo!("check the result of `x.get` for indices 0, 1, 2 and 3"); } #[test] fn test_first_mut() { let mut x: NonEmptyVec<i32> = NonEmptyVec::new(5); todo!("use `x.first_mut()` to modify the first item, and then assert that `x.first()` returns the modified value."); } #[test] fn test_last_mut() { let mut x: NonEmptyVec<i32> = NonEmptyVec::new(5); x.push(10); todo!("use `x.last_mut()` to modify the last item, and then assert that `x.last()` returns the modified value."); } #[test] fn test_pop() { let mut x: NonEmptyVec<i32> = NonEmptyVec::new(5); x.push(10); x.push(15); todo!("call `x.pop()`, and verify that the popped item is 15, and the remaining values are 5 and 10."); } #[test] fn test_pop_single_item() { let x: NonEmptyVec<i32> = NonEmptyVec::new(5); todo!("call `x.pop()`, and verify that the popped item is 5, and that there are no remaining values."); } } }