Most of my writings about Rust come from a JS/TS developer’s point of view. Intuitively, when you learn a new language through another, you tend to map concepts between the two. For example, a struct in Rust might map to an interface or type in TypeScript. Doing this makes it easier to consume knowledge in the new language because the concept suddenly feels familiar. But this pattern of learning introduces a subtle problem.
Once you get used to constantly mapping ideas, it becomes harder to truly grasp concepts in the new language that don’t have a direct equivalent in the one you already know. This was the hurdle I ran into with slices in Rust.
This short article assumes a basic understanding of Rust concepts such as references, borrowing, and ownership.
A common Rust pattern
In Rust, it is generally best practice to use an immutable (read-only) reference when writing a function that does not need to mutate its argument. To illustrate this, let’s write a function that accepts a full name and returns just the first name.
We might end up with something like this:
fn get_first_name(full_name: &str) -> &str {
full_name
.split_whitespace()
.next()
.unwrap_or("")
}
What’s going on here?
The get_first_name function:
- Borrows a string slice (&str); it does not take ownership.
- Splits the string by whitespace into words.
- Takes the first word (if any).
- If there are no words (i.e. the string is empty or contains only spaces), it returns "".
- It returns a slice of the original string, not a new String.
Everything makes sense… except that last bullet point. What do you mean “it returns a slice of the original string, not a new string”?
Let’s unwrap unpack 😌😉
What does “returning a slice” actually mean?
Let me say the same thing using different words: The function is not creating a new string. Instead, it is simply pointing to a portion of the existing one. So if our original string is "Lex Luthor", a slice could refer to:
- "Lex"
- "Luthor"
- "thor"
- "ex Lu"
- or even "Lex Luthor" (the entire string)
All of these are just views into the same underlying string data.
The JavaScript mental model (this helps)
If you’re coming from JavaScript, your brain probably jumps straight to substrings. Yep—that’s a very good instinct.
A substring is a part of another string. Its start and end indices fall within the bounds of the original string. If the start is 0 and the end is string.length, then the substring represents the entire original string. That’s conceptually how slices work in Rust too—but with one important difference:Slices are references, not new values. This distinction is crucial.
Why slices exist at all
If you already have a reference to a string, and you want to refer to part of that string, you could allocate a new string and copy the data into it. But that would mean:
- allocating new memory
- copying bytes
- doing extra work you don’t actually need
Rust looks at this and says: Why not just reference a portion of the original data instead? That way there is no copying, no new memory allocation, and everything stays fast and explicit. That is exactly why slices exist.
Slices aren’t just for strings
Slices work with arrays too, and the syntax looks very similar.
With strings:
let original_value = String::from("Hello world");
let slice = &original_value[1..7];
Here, slice is a &str pointing to "ello w" inside original_value.
With arrays:
let ages = [13, 21, 37, 4, 55];
let slice = &ages[2..4];
In this case, slice is a reference to part of the array: [37, 4].
Slices use the form &original_value[start_index..end_index] where start_index is inclusive and end_index is exclusive. So you slice from start_index up to (end_index - 1). You can also omit one or both indices:
-
&value[..]→ the entire value -
&value[..3]→ from the start to index 2 -
&value[3..]→ from index 3 to the end
Final thoughts
Slices felt strange to me at first because I kept trying to force them into familiar JS concepts. Once I stopped thinking in terms of “new values” and started thinking in terms of references to existing data, everything clicked.
If you want to go deeper, the official Rust book explains slices beautifully and in more detail here, including one powerful example why you should use slices:
Top comments (0)