Strings Exercises
Overview
These exercises cover Rust’s two main string types: String (owned, growable) and &str (borrowed slice).
strings1 - Creating Owned Strings
Concept: The String type
fn current_favorite_color() -> String {
// Two equivalent ways to create a String:
"blue".to_string()
// or: String::from("blue")
}
fn main() {
let answer = current_favorite_color();
println!("My current favorite color is {answer}");
}Key Takeaways:
Stringis an owned, heap-allocated, growable string&str(string slice) is a borrowed view into string data- Convert
&str→Stringwith.to_string()orString::from()
| Type | Ownership | Mutability | Location |
|---|---|---|---|
String | Owned | Can be mut | Heap |
&str | Borrowed | Immutable | Usually stack/static |
strings2 - String References and Coercion
Concept: Deref coercion from &String to &str
fn is_a_color_word(attempt: &str) -> bool {
attempt == "green" || attempt == "blue" || attempt == "red"
}
fn main() {
let word = String::from("green");
if is_a_color_word(&word) {
// ^ &String → automatically coerced to &str
println!("That is a color word I know!");
} else {
println!("That is not a color word I know.");
}
}Key Takeaways:
- Functions often take
&strto accept both&Stringand&str &Stringis automatically coerced to&str(deref coercion)- This is why
&stris preferred in function parameters — it’s more flexible
Coercion Flow:
String → &String → &str
(borrow) (deref coerce)💡 Best Practice: Use
&strin function parameters unless you need ownership.
strings3 - String Manipulation Methods
Concept: Common string operations — trim, format, replace
fn trim_me(input: &str) -> &str {
input.trim() // Removes leading and trailing whitespace
}
fn compose_me(input: &str) -> String {
// format! is like println! but returns a String
format!("{input} world!")
}
fn replace_me(input: &str) -> String {
input.replace("cars", "balloons") // Returns new String
}Key Takeaways:
.trim()— removes leading/trailing whitespace, returns&strformat!()— likeprintln!but returns aStringinstead of printing.replace("old", "new")— replaces all occurrences, returns newString
| Method | Returns | Modifies Original? |
|---|---|---|
.trim() | &str | No (slice of original) |
format!() | String | N/A (creates new) |
.replace() | String | No (creates new) |
strings4 - String vs &str: Choosing the Right Type
Concept: Understanding when to use String vs &str
fn string_slice(arg: &str) { println!("{arg}"); }
fn string(arg: String) { println!("{arg}"); }
fn main() {
// &str literals
string_slice("blue");
// Converting &str → String (multiple ways!)
string("red".to_string());
string(String::from("hi"));
string("rust is fun!".to_owned());
string("nice weather".into()); // Uses Into trait
string(format!("Interpolation {}", "Station"));
// Slicing a String → &str
string_slice(&String::from("abc")[0..1]); // ⚠️ Byte indexing!
// Methods that return &str
string_slice(" hello there ".trim());
// Methods that return String
string("Happy Monday!".replace("Mon", "Tues"));
string("mY sHiFt KeY iS sTiCkY".to_lowercase());
}Ways to convert &str → String:
| Method | Example |
|---|---|
.to_string() | "hello".to_string() |
String::from() | String::from("hello") |
.to_owned() | "hello".to_owned() |
.into() | "hello".into() |
format!() | format!("{}", "hello") |
Methods that return &str:
.trim(),.trim_start(),.trim_end()- Slicing:
&s[0..3](⚠️ byte indices, not characters!)
Methods that return String:
.replace(),.to_lowercase(),.to_uppercase()
⚠️ Warning: String slicing
&s[0..1]uses byte indices, not character indices! For Unicode-safe indexing, use.chars().nth(n).