Vec<T> in Depth
len() and is_empty()
The .len() and .is_empty() methods return the current number of initialized elements in a Vec<T> and whether that count is zero, executing in $O(1)$ time.
Signatures
impl<T> Vec<T> {
pub const fn len(&self) -> usize;
pub const fn is_empty(&self) -> bool;
}
Because Vec<T> stores len: usize directly in its 24-byte stack header, both .len() and .is_empty() compile to a single register/memory load and are usable in const contexts.
Element Count vs. Byte Size in Memory
Unlike String::len(), which always returns a byte count (because UTF-8 characters have variable byte lengths), Vec::<T>::len() always returns the number of T elements, regardless of size_of::<T>():
| Metric | Expression | Value for vec![10_u64, 20, 30] (cap = 4) |
|---|---|---|
| Initialized element count | v.len() |
3 elements |
| Allocated element capacity | v.capacity() |
4 elements |
| Initialized byte size on heap | std::mem::size_of_val(v.as_slice()) |
$3 \times 8 = 24$ bytes |
| Total allocated byte size on heap | v.capacity() * size_of::<u64>() |
$4 \times 8 = 32$ bytes |
| Stack header size | std::mem::size_of_val(&v) |
24 bytes |
use std::mem::size_of_val;
fn main() {
let mut v: Vec<u64> = Vec::with_capacity(4);
println!("Initial: len={}, is_empty={}", v.len(), v.is_empty());
v.extend([100_u64, 200, 300]);
println!(
"Filled: len={}, is_empty={}, slice_bytes={}",
v.len(),
v.is_empty(),
size_of_val(v.as_slice())
);
}
Initial: len=0, is_empty=true
Filled: len=3, is_empty=false, slice_bytes=24
Valid Index Range Invariant (0..v.len())
At all times, only indices in 0..v.len() are initialized and accessible via v[i] or v.get(i). Even when v.capacity() > v.len(), slots in v.len()..v.capacity() are uninitialized memory and cannot be read through safe indexing.