Пакет
unsafe - это легальный способ сказать компилятору: «Отключи ремни безопасности, я беру управление на себя». С его помощью можно обходить строгую типизацию и напрямую управлять памятью, но любая ошибка приведет к моментальному падению сервиса (Segmentation Fault).Проблема стандартной конвертации
В Go строки (
string) иммутабельны (неизменяемы), а срезы байт ([]byte) можно менять. Когда вы пишете s := string(bytes), Go вынужден копировать всю память. Это делается для того, чтобы вы не смогли изменить исходный массив и случайно поменять символы в строке. В высоконагруженных местах (парсинг JSON, HTTP-роутеры) эти копирования плодят мусор и съедают CPU.Zero-allocation конвертация (Go 1.20+)
Долгое время разработчики занимались черной магией, жонглируя внутренними структурами
StringHeader и SliceHeader через указатели. С версии Go 1.20 в язык добавили элегантные функции unsafe.String и unsafe.Slice.
import "unsafe"
// Из []byte в string без копирования памяти
func BytesToString(b []byte) string {
if len(b) == 0 {
return ""
}
// Говорим Go: "Смотри на этот кусок памяти как на строку"
return unsafe.String(&b[0], len(b))
}
// Из string в []byte без аллокаций
func StringToBytes(s string) []byte {
if len(s) == 0 {
return nil
}
return unsafe.Slice(unsafe.StringData(s), len(s))
}
В чем смертельная опасность?
Вы обманули компилятор, но физика осталась прежней. Если вы превратили
string в []byte с помощью unsafe, а затем попытались изменить этот срез (например, b[0] = 'X'), ваша программа мгновенно упадет. Строки часто хранятся в защищенной от записи секции памяти (read-only). Попытка записи туда вызывает панику на уровне операционной системы, которую невозможно перехватить через recover().Когда это реально нужно?
• Написание сверхбыстрых логгеров (популярные библиотеки вроде
zap или zerolog используют это под капотом).• Парсинг потоковых сетевых протоколов, где вы просто читаете миллионы пакетов без их модификации.
• Только тогда, когда
pprof явно показал, что функция runtime.slicebytetostring является главным узким местом приложения.GC и устаревший API
Если вы поддерживаете легаси-код на старых версиях Go, где используется
reflect.StringHeader с полем Data uintptr - срочно переписывайте. Garbage Collector в Go не видит связи между uintptr и реальным объектом в памяти. При неудачном тайминге GC мог очистить память, пока вы с ней работали. Новые методы unsafe.String сохраняют ссылочную целостность для сборщика мусора.#golang #unsafe #performance #underhood #hardcore
📲 Мы в MAX
👉 @golang_lib