The unsafe Package
TL;DR
Go is a “memory-safe” language. It protects you from reading arbitrary memory addresses (which causes Segfaults in C/C++). However, for extreme performance optimization or interacting with C libraries (cgo), the unsafe package allows you to turn off the safety nets, grab raw memory addresses, and cast data between completely unrelated types with zero CPU overhead.
Mental Model
How It Works
The core of the package is unsafe.Pointer.
In normal Go, you cannot convert a pointer to an int (*int) into a pointer to a float64 (*float64). The compiler forbids it.
unsafe.Pointer acts as a magical bridge.
- Convert
*inttounsafe.Pointer. - Convert
unsafe.Pointerto*float64. - You just tricked the compiler. You can now read integer memory as if it were a float!
WARNING: If the Garbage Collector runs while you are manipulating raw pointers, it might move the memory, leaving your unsafe pointer pointing to garbage data, causing catastrophic data corruption.
Example: Zero-Allocation String to Bytes
The most common use of unsafe in high-performance libraries is converting a string to a []byte. Normally, []byte("hello") allocates brand new memory and copies the string. unsafe allows the byte slice to point directly to the read-only string memory.
package main
import (
"fmt"
"unsafe"
)
// Converts string to []byte without memory allocation
func unsafeStrToBytes(s string) []byte {
// A string in memory is just a pointer and a length.
// We grab a pointer to the string itself.
ptr := unsafe.StringData(s)
// We force Go to construct a byte slice header that points
// to the exact same memory address.
return unsafe.Slice(ptr, len(s))
}
func main() {
s := "Hello High Performance World"
// Instantaneous! Zero allocations!
b := unsafeStrToBytes(s)
fmt.Println(string(b))
// DANGER! Strings are read-only in Go.
// Because our byte slice points to string memory,
// if we try to modify the byte slice: b[0] = 'h',
// the entire program will crash with a segfault!
}
Common Interview Questions
Should I use unsafe to make my web app faster?
No. 99.9% of Go developers should never import unsafe. It is used by the authors of the standard library, database drivers, and ultra-high-throughput JSON parsers (like sonic or fasthttp). The risk of memory corruption and undefined behavior across different CPU architectures (ARM vs x86) heavily outweighs the nanoseconds saved for standard applications.
What does unsafe.Sizeof do?
It returns the exact number of bytes a variable takes up in memory. This is highly dependent on struct alignment and padding. For example, a struct with int8, int64, int8 might take up 24 bytes due to padding, but if you rearrange it to int64, int8, int8, unsafe.Sizeof will show it only takes 16 bytes!