Strings and Text Processing

String vs. &str

String and &str are complementary UTF-8 types that parallel the relationship between Vec<T> and &[T]: String owns and mutates a growable heap buffer, while &str borrows an immutable view into UTF-8 text.

Side-by-Side Comparison

Dimension String &str
Ownership Owned (Drop frees the heap buffer) Borrowed view (no cleanup on drop)
Mutability & growth Growable (.push(), .push_str(), .clear()) Fixed length; immutable bytes
Stack size (64-bit) 24 bytes (ptr, len, capacity) 16 bytes (ptr, len)
Backing storage Always heap-allocated (when capacity > 0) Binary .rodata, heap, or stack
Implements Copy? No (moves or clones heap buffer) Yes (copies the 16-byte fat pointer in $O(1)$)
Parallel collection type Vec<u8> &[u8]
s: String (24 B on stack)
+---------------+---------------+---------------+
| ptr           | len = 11      | capacity = 16 |
+-------+-------+---------------+---------------+
        |
        v
Heap: [ 'h', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd', _, _, _, _, _ ]
        ▲                             ▲
        |                             |
slice1: &str (ptr, len = 5)   slice2: &str (ptr + 6, len = 5)

Why Function Parameters Should Prefer &str Over &String

Accepting &str as a function parameter allows callers to pass both string literals (&'static str), substrings (&s[a..b]), and borrowed String values (&my_string, via deref coercion) without allocating:

// Accepts `&str`, `&String` (via Deref), and string slices `&s[..]`:
fn has_prefix(text: &str, prefix: &str) -> bool {
    text.starts_with(prefix)
}

fn main() {
    let owned = String::from("production-db-01");
    let literal = "staging-db-01";

    println!("From &String: {}", has_prefix(&owned, "prod"));
    println!("From &str:    {}", has_prefix(literal, "prod"));
    println!("From slice:   {}", has_prefix(&owned[11..], "db"));
}
From &String: true
From &str:    false
From slice:   true

Choosing Between String, &str, and Cow<'a, str>

Scenario Recommended Type
Read-only function parameter &str (or impl AsRef<str>)
Function builds and returns new text String
Struct field that must own its data without lifetime parameters String (or Box<str> if never mutated)
Zero-copy parser struct tied to an input buffer's lifetime 'a &'a str
Function usually returns input unchanged, but occasionally allocates std::borrow::Cow<'a, str>