Use the built-in trim(), trim_start(), and trim_end() methods on string slices (&str) to remove leading, trailing, or both types of whitespace. These methods return a new string slice pointing to the trimmed portion of the original data without allocating new memory, making them efficient for read-only operations.
For mutable String types, use trim_start_mut() and trim_end_mut() to modify the string in place, which avoids allocation entirely by shrinking the string's length.
fn main() {
let s = " hello world \n";
// Returns a &str slice (no allocation)
let trimmed = s.trim();
println!("Trimmed: '{}'", trimmed); // Output: "hello world"
let start_trimmed = s.trim_start();
let end_trimmed = s.trim_end();
// In-place modification for String
let mut mutable_s = String::from(" rust ");
mutable_s.trim_start_mut();
mutable_s.trim_end_mut();
println!("Mutable: '{}'", mutable_s); // Output: "rust"
}
If you need to remove specific characters other than standard Unicode whitespace, use the trim_matches() method with a character or a closure. This is useful when dealing with custom delimiters or non-standard whitespace characters.
fn main() {
let s = "###hello###";
// Trim specific characters
let trimmed = s.trim_matches('#');
println!("Trimmed chars: '{}'", trimmed); // Output: "hello"
// Trim using a closure for complex logic
let s2 = " hello ";
let trimmed_custom = s2.trim_matches(|c: char| c.is_whitespace() || c == ' ');
println!("Custom trim: '{}'", trimmed_custom); // Output: "hello"
}
Remember that trim() and its variants do not modify the original string; they return a slice. If you need to store the result in a String, you must explicitly convert the slice using .to_string() or .to_owned(). This distinction is crucial for managing memory ownership correctly in Rust.
fn main() {
let original = " data ";
// Convert slice to owned String
let owned: String = original.trim().to_string();
println!("Owned: '{}'", owned);
println!("Original unchanged: '{}'", original);
}