Как сериализовать данные в последовательность байт в Go
Что проверяют
Знаете ли вы, что сериализация в Go это выбор формата под задачу, а не только json.Marshal. Следом спрашивают, чем JSON отличается от gob и protobuf по скорости, размеру и совместимости с другими языками.
Как отвечать
Назовите основные варианты и когда каждый уместен:
encoding/json:json.Marshalвозвращает[]byte, поля управляются тегами вродеjson:"name,omitempty". Сериализуются только экспортируемые поля,[]byteкодируется в base64, всё работает на рефлексии, поэтому не быстро. Для потока естьjson.NewEncoder(w)поверх любогоio.Writer;encoding/gob: бинарный формат только для Go. Поток самоописываемый:gob.Encoderотправляет описание типа один раз, дальше только значения. Подходит для обмена между Go-сервисами, другие языки его не читают;encoding/binary: значения фиксированного размера с явным порядком байт,binary.BigEndian.PutUint32,binary.Write, varint черезbinary.AppendUvarint. С Go 1.23 естьbinary.Append,binary.Encodeиbinary.Decodeдля работы со срезом безio.Writer;- protobuf:
proto.Marshalизgoogle.golang.org/protobuf, компактно, схема в.proto, совместимость между языками и версиями полей. Выбор для gRPC и долгоживущих контрактов; - свой формат: тип реализует
encoding.BinaryMarshalerс методомMarshalBinary() ([]byte, error), и его подхватит, например, gob.
Хороший ответ заканчивается критериями: человекочитаемость и отладка за JSON, размер и скорость за protobuf или msgpack, фиксированный бинарный протокол за encoding/binary.
Где спотыкаются
Пишут поля с маленькой буквы и удивляются пустому {}. Неэкспортируемые поля encoding/json молча пропускает.
Кастуют структуру в байты через unsafe. Такой дамп зависит от выравнивания, порядка байт и архитектуры, а указатели внутри на другой стороне вообще бессмысленны.
Забывают про обратное преобразование. JSON без схемы в map[string]any превращает все числа в float64, и int64 больше 2^53 теряет точность, если не включить Decoder.UseNumber().