In Rust, <span>str</span> and <span>String</span> are two core types for handling text data, and they have essential differences in memory management, ownership, and mutability. The table below summarizes their core differences for quick understanding:
| Feature | <span>String</span> |
<span>str</span> (<span>&str</span>) |
|---|---|---|
| Ownership | Owns the data | No ownership, it is a borrowed reference |
| Mutability | Mutable | Immutable |
| Storage Location | Data is stored on the heap | Data can exist in static memory (like literals) or as a view of heap data (like a part of a <span>String</span> reference) |
| Memory Management | Allocated dynamically on the heap, can grow automatically | Does not involve memory allocation, is a dynamically sized type (DST), typically used through a reference <span>&str</span> |
| Performance Characteristics | Operations may involve memory allocation and copying, relatively high overhead | Very efficient, only passing pointers and lengths, no extra overhead |
| Typical Use Cases | Scenarios where string data needs to be dynamically constructed, modified, or owned | Function parameters, string literals, slicing operations, or read-only access to existing strings |
Detailed Explanation of String
<span>String</span> is a mutable string type provided by the standard library, with data stored on the heap, ownership, and a dynamically changing length.
-
Creating a
<span>String</span>:
- Creating from a literal:
let s = String::from("Hello"); let s = "Hello".to_string();
- Creating an empty string and appending content:
-
let mut s = String::new(); s.push_str("Hello");
Modification and Operations: <span>String</span> supports various modification operations, such as:
let mut s = String::from("Hello");
s.push_str(" World!"); // Append string slice
s.push('!'); // Append character
s.replace("World", "Rust"); // Replace part of the content
These operations may trigger reallocation of the underlying buffer to accommodate more data.
Detailed Explanation of str (&str)
<span>str</span> is Rust’s string slice type, which is itself a dynamically sized type (DST) and is typically used as an immutable reference <span>&str</span>. It represents a read-only view of a valid UTF-8 encoded text.
-
Creating an
<span>&str</span>:
- The type of string literals is usually
<span>&'static str</span>:<span>let s: &str = "Hello";</span> - Borrowing from a
<span>String</span>:let string = String::from("Hello"); let slice: &str = &string
- Getting a partial slice (substring):
let s = "Hello"; let sub: &str = &s[0..2]; // "He" (note that slice boundaries must be on character boundaries)
Common Operations: <span>&str</span> supports slicing, searching, and other read-only operations, but cannot directly modify its content.
let greeting = "Hello, Rust!";
println!("Length in bytes: {}", greeting.len());
if let Some(idx) = greeting.find('R') { println!("'R' found at index: {}", idx); }
Mutual Conversion
<span>String</span> and <span>&str</span> can be easily converted to each other:
-
<span>&str</span>to<span>String</span>: Use<span>to_string()</span>or<span>String::from()</span>. This allocates new memory on the heap and copies the data.let slice: &str = "hello"; let owned_string: String = slice.to_string(); // or String::from(slice) -
<span>String</span>to<span>&str</span>: Use<span>&</span>or<span>as_str()</span>method. This incurs no overhead, just creates a view pointing to the original<span>String</span>data.<span>let s = String::from("hello"); let slice: &str = &s // or s.as_str()</span>
Usage Scenarios
-
Prefer using
<span>&str</span>as function parameters: This allows the function to accept both references to<span>String</span>(<span>&String</span>will be automatically coerced to<span>&str</span>) and string literals (<span>&'static str</span>), providing greater flexibility.fn print_greeting(greeting: &str) { // Recommended to use &str println!("{}", greeting); } -
Use
<span>String</span>when ownership or modification is needed: For example, when reading content from files or networks, or when dynamic string concatenation is required. -
Be aware of UTF-8 encoding: Rust strings are UTF-8 encoded.
<span>len()</span>returns the number of bytes rather than the number of characters. To get the number of characters, use<span>s.chars().count()</span>. Directly accessing characters by index (like<span>s[0]</span>) is not allowed, as characters may consist of multiple bytes. When slicing strings, ensure that the indices fall on character boundaries, or it will cause a panic.