Quick wins for a faster PC:
Fix the driver behind crashes, sound loss and screen glitchesFind Drivers →Repair Windows errors before they cause bigger problemsFix Now →iTechGuides is reader-supported. When you buy through links on our site, we may earn an affiliate commission. As an Amazon Associate I earn from qualifying purchases. Learn more
Converting a finished Vec<T> to Box<[T]>, or a String to Box<str>, discards the spare capacity the value was still holding. That can reduce what a long-lived value keeps allocated. It is not a guaranteed speed gain, and it is not always free: the conversion can reallocate, and the documentation for the String version warns that it may also copy the bytes. Make the switch only when the contents have stopped growing.
What the conversion removes
A collection has two sizes. Its length is how many elements (for Vec) or bytes (for String) it currently holds. Its capacity is how much room the heap allocation has for more. A vector created with Vec::with_capacity(1000) and then filled with 40 items has a length of 40 and a capacity of 1000, so 960 slots sit allocated but unused.
Vec::into_boxed_slice() consumes the vector and discards that excess capacity, behaving the way shrink_to_fit does. The Rust standard-library documentation for Vec describes this behaviour. String::into_boxed_str() works the same way on the string side, as described in the String documentation.
Free tools Windows power users keep installed
One-click scans. No signup required.
Replacing Vec with Box<[T]>
Converting a vector
let mut readings: Vec<u32> = Vec::with_capacity(1000);
readings.extend_from_slice(&[12, 15, 9]);
let frozen: Box<[u32]> = readings.into_boxed_slice();
assert_eq!(frozen.len(), 3);
After this call, frozen is a fixed-length slice. Pushing, inserting, or otherwise changing its length is no longer possible, which is the point: the type now tells every reader that the contents are final.
#1 Best Overall
Observing the result
Box<[T]> has no capacity() method, so you cannot read the capacity directly from the boxed value. If you need to check it in a test or a diagnostic, convert back with Vec::from(frozen) and call capacity() on the result. Treat that as a measurement technique, not something to do in production code paths.
The no-move case: when len equals capacity
The standard-library documentation states that when len == capacity, a Vec<T> can be converted to and from a Box<[T]> without reallocating or moving the elements. The same documentation is the reason not to promise this in general. If the vector has spare capacity, the conversion has to discard it, and the reallocation or move that discarding requires is not covered by the no-move guarantee.
Rank #2
In practice, a vector built with collect() or with an exact-size allocation is the case most likely to hit the fast path. A vector that was filled by repeated push calls usually has spare capacity left over from its growth steps, so expect a real reallocation there.
Recommended Free Tools
Replacing String with Box<str>
A String stores its text in a heap buffer, and both its length and capacity are measured in bytes, not characters. The word café has four Unicode scalar values but occupies five bytes in UTF-8, so String::len() returns 5 for it. Keep that in mind when you reason about capacity: a capacity number is a byte count and says nothing about how many visible characters fit.
Rank #3
let mut label = String::with_capacity(64);
label.push_str("café");
let frozen: Box<str> = label.into_boxed_str();
assert_eq!(frozen.len(), 5);
The String documentation says that into_boxed_str() discards excess capacity, but also says: “Note that this call may reallocate and copy the bytes of the string.” Do not describe this conversion as zero-copy. The linked page is the nightly build of the documentation; if you target a specific stable release, check that release’s String page for the same wording before you rely on the exact text.
Converting back to a growable type
Converting a boxed slice back into a vector transfers ownership of the existing heap allocation, as stated in the Box documentation. The allocation is the one you already have, but the vector now has the boxed slice’s length as its capacity, so the next push has to grow the buffer and may reallocate. A boxed string converts back to a String with into_string() under the same ownership rules.
Comparing the representations
| Question | Vec<T> / String |
Box<[T]> / Box<str> |
|---|---|---|
| Can the length change? | Yes, through push, insert, or push_str | No, the length is fixed |
| Does the type keep spare capacity? | Yes, unless you shrink it | No, excess capacity is discarded at conversion |
| Is the conversion guaranteed not to reallocate? | Not applicable | Not guaranteed. Vec documents a no-move path only when len equals capacity; String documents that the call may reallocate and copy bytes |
| Can you observe capacity directly? | Yes, with capacity() |
No, convert back to read it |
| Converting back | Not applicable | Transfers the existing allocation; the next growth step may reallocate |
When to keep Vec or String
- The value will receive more elements or text after it is built, such as a buffer that is filled across several request handlers.
- You need to add or remove items later, even occasionally. A conversion you later undo will reallocate on the way back.
- The spare capacity is small or expected to be reused, so the conversion would discard little and possibly reallocate for no real benefit.
- You want to reduce excess capacity but keep the value growable. Call
shrink_to_fit()on theVecorStringinstead. The documentation for both types notes that allocators may provide more memory than requested, so do not treat the resulting capacity as an exact allocator-level size.
Checking the effect in your own program
- Record the length and capacity of the collection just before it is finalized, using
len()andcapacity(). - Convert with
into_boxed_slice()orinto_boxed_str(), and keep the boxed value for the rest of its lifetime. - Measure process memory under a realistic workload with your usual profiler or allocator statistics. The standard-library documentation does not provide benchmark figures for these conversions, so any savings or speed change should come from your own measurements.
If the measured difference is negligible, keep the growable type. The conversion’s value lies in the fixed-length guarantee and in discarding capacity you will never use, and neither depends on the allocation count.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

