What Are Strings in Rust?
In Rust, a string is a sequence of Unicode characters. Rust has two main types for representing strings:
- String (String): A growable, heap-allocated string.
- String Slice (&str): An immutable reference to a string, often referred to as a “string slice.”
Both types have specific use cases and characteristics, and understanding their differences is essential for effective Rust programming.
String vs. String Slice
Feature | String | &str |
---|---|---|
Mutability | Mutable | Immutable |
Storage | Heap | Stack or embedded in String |
Ownership | Owns its data | Borrowed from another string |
Use Case | Dynamic, growable text | Fixed, non-growable text |
Creating Strings in Rust
1. Creating a String
You can create a String using the String: :from function or the .to_string method.
fn main() {
let s1 = String::from("Hello, Rust!");
let s2 = "Welcome".to_string();
println!("String 1: {}", s1);
println!("String 2: {}", s2);
}
2. Creating a String Slice (&str)
String slices are references to string data. They are commonly created using string literals.
fn main() {
let s = "This is a string slice.";
println!("{}", s);
}
String Operations
1. Concatenation
You can combine strings using the + operator or the format! macro.
fn main() {
let s1 = String::from("Hello, ");
let s2 = String::from("Rust!");
let s3 = s1 + &s2; // Note: s1 is moved here
println!("{}", s3);
let s4 = format!("{}{}", s3, " Let's learn more.");
println!("{}", s4);
}
2. Appending
The push
and push_str methods allow adding characters or string slices to a String.
fn main() {
let mut s = String::from("Hello");
s.push('!');
s.push_str(" Welcome to Rust.");
println!("{}", s);
}
3. Iterating Over Strings
Strings in Rust are Unicode-compliant, so you can iterate over characters or bytes.
fn main() {
let s = "Rust";
for c in s.chars() {
println!("{}", c);
}
for b in s.bytes() {
println!("{}", b);
}
}
String Immutability and Memory Management
- String (String): Mutable and allocated on the heap. Ownership is transferred when assigned or passed to functions.
- String Slice (&str): Immutable and does not own the data. Often used for borrowing.
Example of Ownership with String
fn main() {
let s1 = String::from("Rust");
let s2 = s1; // Ownership is moved to s2
// println!("{}", s1); // Error: s1 is no longer valid
println!("{}", s2);
}
String Methods
Rust provides numerous methods for working with strings. Here are some commonly used ones:
1. len
Returns the length of the string in bytes.
fn main() {
let s = String::from("Hello");
println!("Length: {}", s.len());
}
2. is_empty
Checks if the string is empty.
fn main() {
let s = String::new();
println!("Is empty: {}", s.is_empty());
}
3. replace
Replaces a substring with another string.
fn main() {
let s = String::from("Hello, Rust!");
let replaced = s.replace("Rust", "World");
println!("{}", replaced);
}
4. split
Splits a string into parts based on a delimiter.
fn main() {
let s = "Rust is fun";
for word in s.split(' ') {
println!("{}", word);
}
}
5. to_uppercase and to_lowercase
Converts a string to uppercase or lowercase.
fn main() {
let s = String::from("Rust");
println!("{}", s.to_uppercase());
println!("{}", s.to_lowercase());
}
Unicode and Strings
Rust strings are UTF-8 encoded, allowing you to store Unicode text. However, you need to handle multibyte characters carefully.
Accessing Unicode Characters
fn main() {
let s = String::from("नमस्ते"); // Hindi for "Hello"
for c in s.chars() {
println!("{}", c);
}
}