tezvyn:

Compare Go's []byte and Rust's &[u8]

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

Tests memory-model depth: Go slices are GC-managed headers (ptr, len, cap) permitting shared mutation, while Rust &[u8] is a borrow-checked fat pointer (ptr, len) enforcing aliasing-XOR-mutation.

WHAT THIS TESTS: This question probes whether you understand memory representation below the surface syntax and how language design choices shape what a slice actually is. Interviewers want to see that you know Go slices are runtime values with headers while Rust slices are borrow-checked views tied to lifetimes.

A GOOD ANSWER COVERS four things in order. First, memory layout: a Go slice like []byte is a three-word struct containing a pointer to backing array data, a length, and a capacity. A Rust &[u8] is a fat pointer, two words wide, holding a pointer and a length with no capacity because it does not own or manage the backing storage. Second, ownership and lifetime: Go relies on garbage collection, so multiple slices can point to the same backing array and mutate it concurrently without compile-time restriction; Rust enforces aliasing XOR mutation through the borrow checker, meaning a shared slice cannot mutate data and cannot outlive the owner. Third, safety mechanisms: both languages perform runtime bounds checking on indexing, but Rust adds compile-time lifetime and exclusivity guarantees that prevent use-after-free and data races on slice data in safe code. Fourth, re-slicing and growth: Go slices support append and re-slicing within capacity, potentially causing confusing aliasing when underlying arrays overlap; Rust slices are fixed views unless you reborrow a sub-slice, and mutation requires a mutable reference.

COMMON WRONG ANSWERS: Claiming Rust slices are just pointers without mentioning fat pointer layout or lifetime parameters. Saying Go slices are fat pointers rather than header structs. Asserting that Rust does not do bounds checking. Ignoring capacity as a distinguishing field in Go. Treating Rust &[u8] as equivalent to a Go slice in terms of ownership, when Rust explicitly borrows rather than owns or references GC-managed memory.

LIKELY FOLLOW-UPS: How does append in Go interact with overlapping slices? What happens when you pass a slice to a goroutine versus a Rust slice across threads? How do string slices differ, such as Go string headers versus Rust string slices? Why can Go have nil slices but Rust slices cannot be null?

ONE CONCRETE EXAMPLE: Imagine two variables created from the same backing array. In Go, both are independent headers pointing at the same data; writing through one after slicing from the other affects the second if they overlap, and the GC keeps the whole backing array alive as long as any slice references any element. In Rust, you cannot hold a mutable reference to data while any shared reference exists, so overlapping mutable views are impossible in safe code, and the borrow checker ensures the backing storage lives at least as long as any borrowed slice.

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.