Pin and Unpin for safe self-referential async futures
Marcus Chen
Jan 2026
1 tab
use std::pin::Pin;
use std::future::Future;
async fn example() {
println!("Example future");
}
fn spawn_local<F>(future: F)
where
F: Future<Output = ()> + 'static,
{
let pinned = Box::pin(future);
// Runtime would poll pinned future
}
1 file · rust
Explain with highlit
Pin ensures that a value won't move in memory, which is required for self-referential types like async futures. Most async code hides this complexity, but understanding it helps when you hit compiler errors about Unpin. A type is Unpin if it's safe to move even when pinned; most types are Unpin by default. When you write async fn, the compiler generates a state machine that might borrow across .await points, making it !Unpin. You pin futures with Box::pin() or pin!(). I rarely use Pin directly in application code, but it's essential for writing async combinators, custom runtimes, or intrusive data structures. The guarantees enable memory-safe async without garbage collection.