We can't find the internet
Attempting to reconnect
Something went wrong!
Attempting to reconnect
← Smart Pointers and Interior Mutability step 1 of 26
The stack, the heap, and Box<T>
Implement two functions that read values stored in boxes:
pub fn heaviest(items: Vec<Box<[u8]>>) -> usize
pub fn unbox_sum(v: Vec<Box<i64>>) -> i64
heaviest returns the zero-based index of the longest slice. If several
slices have the same maximum length, return the lowest index. Return 0
for an empty vector; in that case, the result does not identify an item.
Only slice lengths matter, not their byte values.
unbox_sum returns the sum of the boxed integers, or 0 for an empty
vector. Inputs stay within i64's range, including intermediate sums when
adding in input order. You do not need wrapping or saturating arithmetic.
For example, slice lengths [2, 4, 4] give index 1, while boxed values
[10, -4] give sum 6. Both functions take ownership of their vectors.
What a box owns
Box<T> owns a value through a pointer. For a non-zero-sized payload, the
box manages a heap allocation. Dropping the box normally drops its contents
and releases that allocation. A zero-sized payload, such as an empty boxed
byte slice, needs no allocation.
The box itself can be a local variable, a struct field or an element in a vector. It is not necessarily stored on the stack. Moving a box transfers ownership without moving its payload to a new allocation.
A box pointing to a sized type, such as Box<i64>, is represented by a
single pointer. A boxed slice also carries its length: Box<[u8]> owns a
sequence whose length is known at runtime. You can call .len() through
the box, just as you would on a borrowed slice.
Copying, borrowing and moving the contents
Dereferencing a box does not always move out its contents. What happens depends on the expression and the payload's type. This example copies an integer and leaves the box usable:
fn main() {
let mut boxed = Box::new(7_i64);
let number = *boxed; // i64 implements Copy.
*boxed = 9;
assert_eq!(number, 7);
assert_eq!(*boxed, 9);
}
A String is not Copy. Rust allows moving it out of an owned box:
fn main() {
let boxed = Box::new(String::from("hello"));
let borrowed: &str = &boxed;
assert_eq!(borrowed, "hello");
let text: String = *boxed;
assert_eq!(text, "hello");
// The contents have moved; `boxed` can no longer be read here.
}
This move-out support is special to Box. You cannot move a String out
through an Rc<String> dereference, since another owner might still need
it. Copying an i64 through Rc<i64> is allowed, just as with Box<i64>.
Fixing the starter
The starter tries let owned: Box<i64> = v[i];. A box is not Copy, and
indexing a vector does not let you move an element out while leaving its
slot uninitialized. The compiler reports E0507.
You have two straightforward options:
- Iterate by reference and copy each
i64through its box. Withfor boxed in &v, use**boxedto reach the integer. - Consume the vector with
into_iter(). Each item is then an ownedBox<i64>, and*boxedcopies its integer before that box is dropped.
For heaviest, borrow the slices while comparing lengths. A loop can keep
the first maximum by updating only when a strictly longer slice appears.
If you use max_by_key, remember that it selects the last maximum on a
tie. Include an explicit tie-breaker to get the lowest index.
When boxing helps
Boxes are useful when you need ownership behind a pointer: for example, a runtime-length slice, a trait object or a link in a recursive structure. A recursive node can itself be sized because its child is stored through a pointer rather than embedded directly. Boxing can also keep a large payload at one address while its owner moves.
For a collection of ordinary integers, Vec<i64> is usually simpler than
Vec<Box<i64>>: the vector already stores its elements in a heap buffer,
so separate boxes add allocations and pointer accesses. Keep the boxed
signature here to practice working with an API that already uses boxes.
Clippy can flag some unnecessary boxing, but a passing lint check does not
establish that an API needs a box. Consider ownership and access patterns
when choosing a type. Submissions must compile, pass the tests and pass
clippy -D warnings.
Your code, saved here
Sign in to access your accepted solutions and saved draft history. You can keep reading the lesson without an account.
Sign in to your accountStuck?
Rust reference solution
Sign in to track your attempts toward unlocking the reference solution.