The superpowers of Unsafe Rust, raw pointers (*const T / *mut T), FFI boundaries, and maintaining soundness invariants.
fn split_at_mut<T>(slice: &mut [T], mid: usize) -> (&mut [T], &mut [T]) {
let len = slice.len();
let ptr = slice.as_mut_ptr();
assert!(mid <= len);
// Safe wrapper around unsafe pointer arithmetic
unsafe {
(
std::slice::from_raw_parts_mut(ptr, mid),
std::slice::from_raw_parts_mut(ptr.add(mid), len - mid),
)
}
}
fn main() {
let mut numbers = vec![10, 20, 30, 40, 50];
let (left, right) = split_at_mut(&mut numbers, 2);
left[0] = 99;
right[0] = 88;
println!("Result: {:?}", numbers);
}Every systems language must occasionally talk directly to hardware, allocate raw memory, or bridge with C libraries. Rust isolates these operations inside `unsafe` blocks.
The safe standard library data structures (`Vec`, `HashMap`, `Arc`, `Mutex`) are all implemented using Unsafe Rust wrapped in 100% sound, safe public APIs.
A raw pointer (`*const T` or `*mut T`) can be null, unaligned, or dangling without error; the compiler only requires an `unsafe` block when you actually dereference (`*ptr`) it.
UB includes: Dereferencing null/dangling pointers, violating aliasing rules (e.g. creating `&mut` to the same memory as an existing reference), creating invalid enum discriminants, or producing uninitialized non-MaybeUninit memory.
// Strict aliasing violation (Instant UB):
let mut x = 5;
let p = &mut x as *mut i32;
unsafe {
let r1 = &mut *p;
let r2 = &mut *p; // UB: Two simultaneous &mut references!
}