Collections: Vectors, Strings, and HashMaps
Learn to use common collection types like Vectors (resizable arrays), Strings (UTF-8 encoded text), and HashMaps (key-value pairs).
Collections: Strings in Rust
Introduction to Strings in Rust
In Rust, strings are UTF-8 encoded text. This means they can represent characters from any language, making them extremely versatile for handling text data.
Creating Strings
Rust provides different ways to create strings:
- String Literal (
&str
): Immutable string slices that are often hardcoded in your program. They are stored directly in the program's binary. They are efficient but cannot be modified. String
: A growable, mutable, owned string. It's allocated on the heap and can be resized. This is the type you'll typically use when you need to modify a string.
Example: Creating a String
let mut s = String::new(); // Create an empty String
let data = "initial contents";
let s = data.to_string(); // Convert a &str to a String
// or
let s = String::from("initial contents"); // Another way to convert a &str to a String
Manipulating Strings
The String
type provides methods for modifying and working with string data.
- Appending to a String:
let mut s = String::from("foo"); s.push_str("bar"); // Appends a string slice (&str) s.push('!'); // Appends a single character (char)
- Concatenation:
You can use the
+
operator to concatenate strings. Note that it takes ownership of the first string (String
) and borrows the second string slice (&str
). This means the first string is moved and can no longer be used after the concatenation.let s1 = String::from("Hello, "); let s2 = String::from("world!"); let s3 = s1 + &s2; // s1 has been moved here and can no longer be used //Note: the type of s2 is &String but the &String is coerced to a &str when we call the add method // This is because the add method is defined to take a &str, not a &String
For more complex concatenation or when you want to avoid taking ownership, use the
format!
macro.let s1 = String::from("tic"); let s2 = String::from("tac"); let s3 = String::from("toe"); let s = format!("{}-{}-{}", s1, s2, s3); //No ownership is taken
- Replacing Substrings:
let mut s = String::from("Hello World"); s.replace("World", "Rust"); // Returns a new String with the replacement
Working with String Data
Strings in Rust are UTF-8 encoded, so it's important to understand how to access and iterate over characters.
- Iterating over Characters:
let s = String::from("नमस्ते"); // Hindi greeting for c in s.chars() { println!("{}", c); }
- Iterating over Bytes:
let s = String::from("नमस्ते"); for b in s.bytes() { println!("{}", b); // Prints the UTF-8 byte values }
- Slicing strings
let s = String::from("hello world"); let hello = &s[0..5]; // hello is now &str referencing "hello" //Note: you must be careful when slicing Rust strings, // because it can crash your program if the characters are not encoded in a byte width that you'd expect
Common String Operations
- Getting the Length of a String:
let s = String::from("Hello"); let length = s.len(); // Returns the length in bytes println!("Length: {}", length);
- Checking if a String is Empty:
let s = String::new(); let is_empty = s.is_empty(); println!("Is empty? {}", is_empty);
- Converting to Lowercase/Uppercase:
let s = String::from("Hello World"); let lowercase = s.to_lowercase(); // Returns a new String in lowercase let uppercase = s.to_uppercase(); // Returns a new String in uppercase
Important Considerations
- UTF-8 Encoding: Rust strings are always valid UTF-8. Be aware of this when performing operations that might invalidate the encoding, such as slicing.
- Ownership: Pay close attention to ownership rules, especially when concatenating strings or passing them to functions.
- String vs. &str: Understand the difference between the owned
String
and the string slice&str
, and choose the appropriate type for your use case.