tezvyn:

Rust's `unsafe` Keyword: Five Superpowers, Zero Guarantees

AI-drafted, machine-checkedSource: doc.rust-lang.orgintermediate

Rust's `unsafe` keyword lets you bypass certain compile-time memory safety guarantees for low-level tasks like OS interaction or FFI. The footgun is thinking it disables all safety; it only enables five specific 'superpowers,' making you responsible for…

WHY IT EXISTS Rust's compiler is conservative by design; it will reject some valid programs if it cannot prove their memory safety. Unsafe Rust provides an escape hatch for these situations. It also exists because underlying computer hardware is inherently unsafe, and to perform low-level tasks like interacting with an operating system or writing one, programmers need a way to perform operations that Rust's safety guarantees would otherwise forbid.

THE MENTAL MODEL Think of unsafe as a contract where you tell the compiler, "Trust me, I know what I'm doing." You are temporarily disabling certain compile-time safety checks in a specific block of code. In return for this power, you take on the full responsibility for ensuring memory safety yourself. It is not a switch to turn off all of Rust's safety features; for instance, the borrow checker still operates on regular references within an unsafe block.

HOW IT WORKS You use the unsafe keyword to create a block or declare a function. Inside this context, you gain five "superpowers" unavailable in safe Rust: dereferencing a raw pointer, calling an unsafe function or method, accessing or modifying a mutable static variable, implementing an unsafe trait, and accessing fields of a union. A key concept is the raw pointer (*const T and *mut T), which is distinct from a reference. Raw pointers are allowed to ignore borrowing rules, can be null, and are not guaranteed to point to valid memory, giving you C-like flexibility and risk.

WHEN TO USE IT Use unsafe when you need to interface with code outside Rust's guarantees, such as calling C functions (FFI), or when interacting directly with hardware. It's also necessary for implementing certain high-performance data structures where the logic is safe, but the compiler cannot verify it. The best practice is to keep unsafe blocks small and wrap them in a safe, public API, so users of your code don't need to use unsafe themselves.

WHEN NOT TO USE IT Avoid using unsafe as a shortcut to silence the compiler or bypass the borrow checker when you don't understand an error. Any error related to memory safety in a Rust program must originate within an unsafe block, so keeping these blocks minimal is crucial for debugging. If a safe alternative exists, always prefer it.

ONE CANONICAL EXAMPLE To interact with raw pointers, you must use an unsafe block. You can create raw pointers from references, but to read the value they point to (dereference them), the operation must be marked as unsafe because the pointers might be null or invalid. For example: let mut x = 10; let ptr = &x as *const i32; unsafe { assert_eq!(*ptr, 10); }.

Read the original → doc.rust-lang.org

Get five bites like this every day.

Tezvyn delivers a daily feed of 60-second tech bites with quizzes to lock in what you learn.