Skip to main content

Strings

In Rust, text handling is powerful but strict. This is because Rust guarantees memory safety and Unicode correctness.

Rust mainly uses two types for text:

  1. String – an owned, growable string
  2. &str – a string slice, borrowed view of a string

Understanding the difference is crucial.

String in Rust

  • A heap-allocated, growable, mutable string
  • Stores text as UTF-8
  • Owns its data
let mut s = String::from("Hello");

Key Characteristics

FeatureString
MemoryHeap
Mutable✅ Yes
OwnershipOwns the data
UTF-8✅ Yes

Creating a String

let s1 = String::from("Hello");
let s2 = "World".to_string();

Both create a String.

Modifying a String

Appending text

let mut s = String::from("Hello");
s.push('!'); // single character
s.push_str(" World"); // string slice

Result: Hello! World

Concatenation: Using + operator

let s1 = String::from("Hello ");
let s2 = String::from("Rust");

let s3 = s1 + &s2;

Important:

  • s1 is moved
  • s2 is borrowed

Why? Because + is actually: fn add(self, s: &str) -> String

Using format! macro (recommended)

let s1 = String::from("Hello");
let s2 = String::from("Rust");

let s3 = format!("{} {}", s1, s2);
  • No ownership issues
  • Cleaner code

String Slices (&str)

A string slice is a reference to part (or all) of a string.

let s = String::from("Hello World");
let slice = &s[0..5];

slice is of type &str

Key Characteristics

Feature&str
Ownership❌ No
Mutable❌ No
MemoryStack reference
UTF-8✅ Yes

String Literals Are Slices

let s = "Hello Rust";

This is not a String. It is a &'static str (stored in the binary).

String Slicing Syntax

let s = String::from("Hello World");

let hello = &s[0..5];
let world = &s[6..11];

Shorthand versions

let hello = &s[..5];    // from start
let world = &s[6..]; // to end
let full = &s[..]; // entire string

UTF-8 and Slicing Rules (Very Important!)

Rust strings are UTF-8 encoded, so indexing is NOT allowed.

This is illegal:

let s = String::from("Hello");
let c = s[0]; // ❌ compile-time error

Why?

  • Characters may take more than 1 byte

Invalid UTF-8 Slice Example

let s = String::from("नमस्ते");
let slice = &s[0..1]; // ❌ runtime panic

Because characters like use multiple bytes.

Safe Way: Iterate Over Characters

let s = String::from("नमस्ते");

for c in s.chars() {
println!("{}", c);
}

Converting Between String and &str

String ➡️ &str

let s = String::from("Hello");
let slice: &str = &s;

&str ➡️ String

let slice = "Hello";
let s = slice.to_string();

or

let s = String::from(slice);

Function Parameters: Best Practice

Prefer &str over String

fn greet(name: &str) {
println!("Hello, {}", name);
}

Why?

  • Accepts both String and &str
  • Avoids unnecessary ownership transfer
let s = String::from("Rust");
greet(&s);
greet("World");

Summary Table

FeatureString&str
Owns data
Mutable
Heap allocated
UTF-8
Common useDynamic textFunction parameters