Ownership & Borrowing in Request Handlers
Understand how Rust's ownership model affects your Actix Web handlers and application state.
Learning Objectives
- Understand why you must clone state
- Learn about Arc<Mutex<T>>
- Avoid borrow checker errors in handlers
##Ownership: Rust's superpower
Rust manages memory without a garbage collector and without manual free calls. It does this with three simple rules about ownership. They feel strange at first, but they are exactly why Actix Web servers are fast and safe.
#The three rules
- Every value has exactly one owner.
- There can only be one owner at a time.
- When the owner goes out of scope, the value is dropped (its memory is freed).
fn main() {
let name = String::from("Ada"); // `name` owns the string
let other = name; // ownership MOVES to `other`
// println!("{name}"); // error: value moved
println!("{other}");
}After let other = name;, the variable name is no longer valid. Rust moved the string instead of copying it, so there is never a question about who must free it.
#Borrowing with references
Moving everywhere would be annoying. Instead you can borrow a value with a reference, which lets you use it without taking ownership:
fn length(text: &String) -> usize {
text.len()
}
fn main() {
let s = String::from("hello");
let n = length(&s); // lend `s`, do not give it away
println!("{s} has {n} bytes");
}There are two kinds of borrows:
&T, a shared reference. You can have many at once, and they are read-only.&mut T, an exclusive reference. You can have only one, and nothing else may read the value at the same time.
fn add_exclamation(text: &mut String) {
text.push('!');
}
fn main() {
let mut s = String::from("hi");
add_exclamation(&mut s);
println!("{s}"); // hi!
}This "many readers or one writer" rule prevents data races at compile time.
#Copy versus move
Small simple types such as integers, booleans and char implement Copy, so assigning them copies the value. Types that own heap memory, like String and Vec, are moved.
#Why this matters in Actix Web
- Handlers receive owned values from extractors (
web::Json<T>,web::Path<T>), so you can freely use them. - Closures given to
HttpServer::newoften needmovebecause they must own what they capture. - Shared state uses
web::Data, which is anArc.Arcgives shared ownership across threads: cloning it only copies a pointer.
When the compiler says "value moved" or "cannot borrow as mutable", it is not being difficult. It is pointing at a real bug that would have crashed other languages at runtime.
Interactive Code Inspector
Select any highlighted line of code below to deeply inspect its mechanics, understand why it exists, and what happens if you change it.
"What If?" Experiment
Learning by doing. Modify the code to see what happens.
Trigger and read a borrow checker error.
Compile it and read the error message.
The compiler reports "borrow of moved value: a" and suggests cloning.
Explanation: Rust's errors point out exactly which line moved the value, which is the fastest way to learn the rules.
Common Mistakes
Anticipate and avoid these frequent pitfalls when working with this concept.
Using a value after moving it
Passing a String by value gives away ownership.
Explanation: Pass a reference (&s) when the function only needs to read the value, so you keep ownership.
Two mutable borrows at once
Rust forbids aliasing a mutable reference.
Explanation: Finish using the first mutable borrow before creating the second, or restructure so only one place edits the value.
Practical Exercise
Fix the borrow errors
TaskMake the program compile by borrowing instead of moving, then print the string and its length.
Requirements
- Write a function that takes &str and returns its length
- Call it without giving away the String
- Print both the string and its length
Need a hint?
Try solving the exercise in your local environment first. Once you have a solution, or if you get completely stuck, reveal the answer.
Real-World Application
Fast Actix Web servers rely on ownership: request data is moved into handlers without copying, and shared resources like database pools are passed around as cheap Arc clones.
Key Takeaways
- Each value has one owner and is dropped when the owner goes out of scope.
- Assigning or passing a String moves it; use & to borrow instead.
- You can have many &T borrows or exactly one &mut T at a time.
- web::Data uses Arc for shared ownership across worker threads.
Finished reading?
Mark this lesson as done to track your progress and earn XP.