Question
I cannot find in the Vec<T> documentation how to retrieve a slice from a specific range.
Is there something like this in Rust’s standard library?
let a = vec![1, 2, 3, 4];
let suba = a.subvector(0, 2); // should contain [1, 2]
Short Answer
By the end of this page, you will understand how to get a slice from a Vec<T> in Rust, how range syntax works, the difference between borrowing a slice and creating a new vector, and how to avoid common indexing mistakes.
Concept
In Rust, a Vec<T> is a growable heap-allocated collection, while a slice (&[T]) is a borrowed view into a sequence of elements.
When you want part of a vector, Rust usually does not create a new vector automatically. Instead, it gives you a slice that points to a section of the existing vector.
For example:
let a = vec![1, 2, 3, 4];
let suba = &a[0..2];
Here, suba is a slice of type &[i32], and it refers to the first two elements: [1, 2].
This matters because:
- It avoids unnecessary copying.
- It is efficient.
- It fits Rust’s ownership and borrowing model.
- It allows functions to work with both arrays and vectors using the same slice type.
If you actually need an independent collection, you can convert the slice into a new Vec<T>:
let a = vec![, , , ];
= a[..].();
Mental Model
Think of a Vec<T> as a full loaf of bread, and a slice as a few pieces cut from it.
- The vector owns the whole loaf.
- A slice is just a view of part of that loaf.
- Taking a slice does not bake a new loaf.
- If you want a separate loaf, you must copy the pieces into a new vector.
So &a[0..2] means: “Let me look at elements starting at index 0 and stopping before index 2.”
Syntax and Examples
Rust uses range syntax with indexing to create slices.
Basic syntax
let slice = &vec[start..end];
startis includedendis excluded
So 0..2 means indices 0 and 1.
Example: get the first two elements
let a = vec![1, 2, 3, 4];
let suba = &a[0..2];
println!("{:?}", suba); // [1, 2]
suba has type:
&[i32]
Example: from a starting index to the end
Step by Step Execution
Consider this example:
let a = vec![10, 20, 30, 40];
let part = &a[1..3];
println!("{:?}", part);
Step by step:
-
let a = vec![10, 20, 30, 40];- A vector is created with four elements.
- Index positions are:
0 -> 101 -> 202 -> 303 -> 40
-
let part = &a[1..3];- Rust reads the range
1..3. - Start at index
1. - Stop before index
3. - That includes elements at indices
1and .
- Rust reads the range
Real World Use Cases
Slicing vectors is useful in many real programs.
Processing part of a dataset
let readings = vec![12, 15, 18, 20, 22, 25];
let recent = &readings[3..];
You might only want the most recent sensor readings.
Pagination or batching
let users = vec!["a", "b", "c", "d", "e"];
let page = &users[0..2];
This can represent one page of results or one batch of records.
Parsing tokens
let tokens = vec!["let", "x", "=", "5", ";"];
let = &tokens[..];
Real Codebase Usage
In real Rust codebases, developers often prefer slices over Vec<T> in APIs when ownership is not needed.
Accept slices in functions
fn average(values: &[f64]) -> f64 {
let total: f64 = values.iter().sum();
total / values.len() as f64
}
This lets callers pass:
- a full vector:
&v - part of a vector:
&v[1..4] - an array slice:
&arr[..]
Validation before slicing
Direct indexing can panic if the range is invalid. In production code, developers often validate lengths first.
fn first_two(values: &[i32]) -> Option<&[i32]> {
if values.len() >= 2 {
Some(&values[..])
} {
}
}
Common Mistakes
1. Expecting a new Vec<T> instead of a slice
This code does not create a new vector:
let a = vec![1, 2, 3, 4];
let suba = &a[0..2];
suba is a slice, not a Vec<i32>.
If you need a new vector:
let suba = a[0..2].to_vec();
2. Forgetting that the end index is excluded
Broken expectation:
let a = vec![1, 2, 3, 4];
let suba = &a[0..2]; // contains [1, 2], not [1, 2, 3]
Comparisons
| Concept | Type | Owns data? | Copies data? | Can panic? | Typical use |
|---|---|---|---|---|---|
&a[0..2] | &[T] | No | No | Yes, if range is invalid | Fast borrowed view |
a[0..2].to_vec() | Vec<T> | Yes | Yes | Yes, if range is invalid | Need an independent collection |
a.get(0..2) | Option<&[T]> | No | No | No |
Cheat Sheet
Quick reference
Get a slice from a vector
let v = vec![1, 2, 3, 4];
let s = &v[0..2];
Result:
[1, 2]
Range rules
start..end→ includesstart, excludesend..end→ from beginning toendstart..→ fromstartto end..→ whole slice
Examples:
&v[..2]
&v[1..]
&v[..]
Types
FAQ
How do I slice a Vec<T> in Rust?
Use range syntax with borrowing:
let part = &vec[0..2];
This returns a slice, not a new vector.
Does slicing a vector copy the data?
No. A slice is just a borrowed view into the original vector.
How do I get a new Vec<T> from part of a vector?
Use .to_vec() on the slice:
let new_vec = vec[0..2].to_vec();
What is the type of &vec[0..2]?
It is &[T], a slice reference.
Can slicing panic in Rust?
Yes. Using an invalid range like &vec[0..10] on a shorter vector will panic.
How can I slice safely without panicking?
Use .get(range):
Mini Project
Description
Build a small Rust program that extracts different parts of a vector and prints them. This demonstrates how slices work, how range syntax behaves, and how to safely access ranges without panicking.
Goal
Create a program that shows borrowed slices, full slices, and safe range access with .get().
Requirements
- Create a vector with at least five numbers.
- Print a slice containing the first two elements.
- Print a slice containing the middle part of the vector.
- Use
.get()to safely try an out-of-range slice. - Create a new owned vector from one slice using
.to_vec().
Keep learning
Related questions
Accessing Cargo Package Metadata in Rust
Learn how to read Cargo package metadata like version, name, and authors in Rust using compile-time environment macros.
Associated Types vs Generic Type Parameters in Rust: When to Use Each
Learn when to use associated types vs generic parameters in Rust traits, with clear rules, examples, and practical API design advice.
Can a Struct Extend Another Struct in Rust? Composition vs Inheritance
Learn how Rust handles struct reuse without inheritance, using composition, traits, and wrapper structs with practical examples.