Rust has two main string types: &str (a string slice) and String (a growable, heap-allocated string). &str is usually used for static or borrowed strings, while String is used when you need to modify or own the string data.
In JavaScript, you often work with strings directly, and most of the time you do not think about whether the string is owned, borrowed, or how it is stored. In Rust, string handling is more precise. This is part of what makes the language powerful and safe.
In this post, I will explain the two types of strings in Rust, how to use them, and how to convert between them. Once you get used to the difference, you will find that Rust’s approach gives you much more control and clarity.
If you have not read about Constants and Immutability or Variables and Mutability, you may want to go through those first, because strings in Rust are variables that must follow Rust’s strict rules.
Two Main String Types in Rust
Rust has two types for handling text:
- &str – Called a “string slice.” It is a reference to a sequence of UTF-8 characters stored somewhere else.
- String – A growable, heap-allocated string. It owns its contents.
You will often see these used together, and you can convert from one to the other.
Example:
let s1: &str = "hello"; // string slice
let s2: String = String::from("hello"); // owned String
When to Use &str
You use &str when:
- The string is known at compile time.
- You want to reference string data without taking ownership.
- You are passing a string to a function that only needs to read it.
Most string literals in Rust are &str. For example:
fn main() {
let greeting = "Hello, Rust!";
println!("{}", greeting);
}
Here, “Hello, Rust!” is a &str.
When to Use String
You use String when:
- You want to create a string at runtime.
- You want to change the string contents.
- You need ownership of the string data.
You can create a String like this:
let mut name = String::from("Alice");
name.push_str(" Smith");
println!("Full name: {}", name);
This is not possible with &str, because &str is immutable and does not own its contents.
Converting Between String and &str
You can convert a String into a &str easily by using a reference:
let s: String = String::from("hello");
let slice: &str = &s;
To convert a &str to a String, use to_string() or String::from():
let slice = "hello";
let s = slice.to_string();
These conversions are common when passing data between functions.
Example Program
fn main() {
let name = "John"; // &str
let mut full_name = String::from(name); // convert to String
full_name.push_str(" Doe"); // modify it
println!("Full name: {}", full_name);
}
This example starts with a string slice, converts it into a growable string, and then adds more text.
String Methods You Should Know
Here are some common operations on strings:
let mut s = String::from("hello");
s.push('!'); // add a character
s.push_str(" world"); // add a string
let length = s.len(); // get length in bytes
let slice = &s[0..5]; // get a substring (be careful: UTF-8 indexing)
You can also loop through characters:
for c in s.chars() {
println!("{}", c);
}
Common Error: Indexing Strings
Rust strings are UTF-8 encoded, so you cannot use s[0] to get the first character. That is because each character might take more than one byte. You can use chars() or get() with ranges to safely access parts of a string.
Summary
Rust separates strings into &str (borrowed) and String (owned and growable). Use &str for simple, read-only text and String when you need control or modification. Learn to convert between them, and practice string operations like push_str, len, and slicing.