tezvyn:

Contrast unsafe in Go versus Rust and the invariants you assume

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

Tests divergent safety philosophies. Go unsafe enables FFI and pointer casting; you guarantee valid memory, alignment, and GC reachability. Rust unsafe unlocks raw pointers and FFI; you manually uphold aliasing and validity invariants behind safe APIs.

WHAT THIS TESTS: This probes your mental model of each language's safety boundary and whether you understand that unsafe transfers specific proof obligations from the compiler to you. It separates people who have read docs from those who have reasoned about GC, aliasing, and abstraction boundaries.

A GOOD ANSWER COVERS: First, Go's unsafe package is a pragmatic tool for pointer arithmetic and cgo within a garbage-collected language. When you use unsafe.Pointer or uintptr, you must guarantee alignment, valid memory, and critically that the GC can still trace object lifetimes. Converting a pointer to uintptr and back is only safe in the same expression because storing a pure integer may hide the reference from the GC. Second, Rust's unsafe keyword is a scoped contract granting five superpowers such as dereferencing raw pointers and calling unsafe functions. The justification is building zero-cost safe abstractions where unsafe is an implementation detail. The invariants you assume are exhaustive: raw pointers must be non-null and aligned, mutable and immutable references must not violate aliasing rules, values must be initialized, and data races must not occur. Third, contrast the cultures: Go trusts you to cooperate with the runtime, while Rust demands proof-like discipline so safe code cannot trigger undefined behavior.

COMMON WRONG ANSWERS: A red flag is asserting that unsafe in Rust turns off the borrow checker. The borrow checker still enforces rules on safe code inside an unsafe block; only the five superpowers bypass checks. Another error is claiming both languages provide unsafe primarily for performance. Go's unsafe is largely for FFI and memory layout, while Rust's unsafe enables patterns the type system cannot express. Treating them as equivalent escape hatches signals shallow understanding.

LIKELY FOLLOW-UPS: Expect questions on testing or auditing unsafe code, which invites discussion of Miri for Rust or boundary testing in Go. You might be asked to rewrite an unsafe block using reflect in Go or safe abstractions in Rust. Another follow-up asks what happens when invariants break, such as undefined behavior in Rust versus a GC crash or heap corruption in Go.

ONE CONCRETE EXAMPLE: Consider parsing a binary protocol into a struct. In Go, you might cast a byte slice header over struct fields with unsafe.Pointer. You must guarantee the slice is large enough, alignment matches, and you do not retain the pointer after the slice is garbage-collected. In Rust, you might call slice::from_raw_parts on an FFI buffer. You must guarantee the pointer is non-null and aligned, the length is correct, the data remains valid for the slice lifetime, and you expose only a safe wrapper so callers cannot violate these assumptions.

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.