When working with text in Rust, it's essential to understand the two primary string types: String
and str
. In this guide, we'll explore the differences between them and how to use them effectively.
Introduction to Strings
A string is a collection of characters. In Rust, the String
type represents a growable, mutable, owned, heap-allocated UTF-8 encoded string. On the other hand, str
(string slice) is an immutable view into a sequence of UTF-8 bytes, usually borrowed from a String
or a string literal.
String Type (String
)
A String
in Rust is a mutable, UTF-8 encoded string that can grow and shrink in size. You can create a String
from a string literal or from another String
using the to_string
method.
let s1: String = "Hello, ".to_string();
let s2: String = String::from("world!");
let s3: String = String::new(); // Dynamic empty string
let combined = s1 + &s2;
println!("{}", combined); // Prints: Hello, world!
One other way to make a String
is called .into()
but it is a bit different because .into()
isn't just for making a String
.
fn main() {
let s4 = "Try to make this a String".into();
// ⚠️type annotations needed, consider giving `s4` a type
let s5: String = "Try to make this a String".into();
// ✅ Now compiler is happy with `String` type
}
Methods on String
String
has various methods for manipulating and working with strings. Some common methods include:
-
push_str
: Appends a string slice to the end of theString
. -
replace
: Replaces a substring with another substring. -
to_uppercase
/to_lowercase
: Converts the string to uppercase or lowercase.
let mut my_string = String::from("Hello, world!");
my_string.push_str(" How are you?");
my_string = my_string.replace("world", "Rust");
println!("{}", my_string.to_uppercase());
// Prints: HELLO, RUST! HOW ARE YOU?
String Slice (&str
)
A str
is an immutable reference to a sequence of UTF-8 bytes. It is usually seen as a borrowed form of a String
or a string literal.
let s: &str = "Hello, world!";
let slice: &str = &s[0..5]; // Take a slice from index 0 to 5 (exclusive)
println!("{}", slice); // Prints: Hello
You can even write emojis, thanks to UTF-8.
fn main() {
let name = "😂";
println!("My name is actually {}", name);
// prints: My name is actually 😂
}
Methods on str
str
also has a variety of methods for manipulating and working with text. Some common methods include:
-
len
: Returns the length of the string. -
is_empty
: Returns true if the string is empty. -
starts_with
/ends_with
: Checks if the string starts or ends with a given substring.
let my_str: &str = "Hello, Rust!";
let my_string: String = String::from("Hello, Rust!");
println!("str Length: {}", my_str.len());
println!("String Length: {}", my_string.len());
println!("str Is empty: {}", my_str.is_empty());
println!("String Is empty: {}", my_string.is_empty());
println!("str Starts with 'Hello': {}", my_str.starts_with("Hello"));
println!("String Starts with 'Hello': {}", my_string.starts_with("Hello"));
Transforming Between String
and str
You can convert a String
to a &str
using the as_str
method or by using the &
operator. Conversely, you can convert a &str
to String
using the to_string
method.
let my_string: String = String::from("Hello");
let my_str1: &str = my_string.as_str();
let my_str2: &str = &my_string;
println!("{}", my_str1); // Prints: Hello
println!("{}", my_str2); // Prints: Hello
let my_str: &str = "World!";
let my_string: String = my_str.to_string();
println!("{}", my_string); // Prints: World!
Concatenating Strings
There are several ways to concatenate strings in Rust, depending on your needs:
- Using the
+
operator (consumes ownership of the first string). - Using the
format!
macro (does not consume ownership of any string). - Using the
push_str
method to append a string slice to aString
. - Using the
push
method to append a single character or string slice to aString
.
let s1 = String::from("Hello, ");
let s2 = String::from("world!");
let combined = s1 + &s2; // Using the + operator
let combined = format!("{}{}", s1, s2); // Using the format! macro
let mut s1 = String::from("Hello,");
let s2 = String::from("world!");
s1.push_str(&s2); // Using the push_str method
let mut s1 = String::from("Hello,");
let s2 = String::from("world!");
s1.push(' '); // Adding a space(' ') Char type
s1.push_str(&s2); // Using the push method
When concatenating strings, be aware of ownership and borrowing rules to avoid issues like moving ownership unintentionally. If you need to concatenate strings in a loop or multiple times, consider using a String
and appending with push_str
for better performance.
Conclusion
Understanding the differences between String
and str
is crucial for writing efficient and safe Rust code when working with strings. By following Rust's ownership and borrowing rules, you can manipulate strings effectively while ensuring memory safety.
Top comments (3)
nice articles !
Thanks 😊
Excellent 👍