Как отдавать сообщения различных типов?
Ссылка скопирована
type Packet struct { Type uint8 Timestamp uint32 Data []byte } func ReadPacket(packet *Packet) error { // somehow read data into the packet return nil } type Message interface {} type VideoMessage struct { Timestamp uint32 Data []byte } type CallMessage struct { CallID uint32 Procedure string } func ReadMessage() (Message, error) { var packet Packet if err := ReadPacket(&packet); err != nil { return err } switch packet.Type { case PacketVideo: return &VideoMessage{ Timestamp: packet.Timestamp, Data: packet.Data, }, nil case PacketUserData: callID, procedure := getCallInfo(&packet) return &UserDataMessage{ CallID: callID, Procedure: procedure, }, nil default: return nil, ErrInvalidPacketType } }
Сейчас ситуация такая: проблема в том, что я постоянно выделяю память для сообщений.
По вводным: есть идея реализовать union тип по примеру C, но тогда нарушится безопасность типов.
Сейчас ситуация такая: либо можно попробовать использовать какой-то пул памяти и выделять место под сообщения там, но я не уверен насчет этого решения
Либо что-то такое
func ReadCallMessage(packet *Packet, mesg *CallMessage) { // read packet into mesg } func main() { for { var packet Packet if err := ReadPacket(&packet); err != nil { continue } switch packet.Type { case PacketCall: mesg := CallMessage{} ReadCallMessage(&packet, &mesg) } } }
Какие варианты решения стоит рассмотреть?
Нужно решить такую задачу?
Заказать помощь
Опишите проблему, и специалист поможет с настройкой, исправлением ошибки или доработкой сайта. Подберём понятный план работ без лишней переписки.
Лучший ответ
1
Другие ответы (0)
Пока нет других ответов. Будьте первым, кто поможет автору.
Ответить на вопроскомментарий
Вам также может быть интересно
VPN
Как правильно настроить vless для Android TV?
1 ответ
Pyrogram
Как правильно зарегистрировать юзер бота в Telegram?
1 ответ
печатные-платы
Как заставить запускаться программу M3.exe от компании Hanxing AOI в инспекционной машине на Windows 7 Pro?
1 ответ
woocommerce
Как отображать при фильтрации товары со значением search параметра visibility: HUSKY — Products Filter for WooCommerce?
1 ответ

В Go обычно не нужно пытаться сделать C-style union ради экономии нескольких аллокаций. Такой подход ухудшит читаемость и безопасность типов. Если у вас реально горячий участок и много пакетов, сначала измерьте профилем, что именно аллокации сообщений являются проблемой. Очень часто основная стоимость не в структуре
VideoMessage, а в буфереData []byte, парсинге и I/O.Базовый идиоматичный вариант через interface нормален:
type Message interface { Kind() uint8 } func (m VideoMessage) Kind() uint8 { return PacketVideo } func (m CallMessage) Kind() uint8 { return PacketUserData }
Но если хотите уменьшить аллокации, можно возвращать значение-обёртку с union-like полями и явным типом:
type Message struct { Type uint8 Video VideoMessage Call CallMessage } func ReadMessage() (Message, error) { var packet Packet if err := ReadPacket(&packet); err != nil { return Message{}, err } switch packet.Type { case PacketVideo: return Message{ Type: PacketVideo, Video: VideoMessage{ Timestamp: packet.Timestamp, Data: packet.Data, }, }, nil case PacketUserData: callID, procedure := getCallInfo(&packet) return Message{ Type: PacketUserData, Call: CallMessage{CallID: callID, Procedure: procedure}, }, nil default: return Message{}, ErrInvalidPacketType } }
Да, это менее красиво, чем interface, зато без выделения под конкретную структуру при возврате указателя. Использование:
msg, err := ReadMessage() if err != nil { return err } switch msg.Type { case PacketVideo: handleVideo(msg.Video) case PacketUserData: handleCall(msg.Call) }
Ещё вариант — передавать обработчик callback-ом, тогда можно вообще не создавать отдельный message object:
func ReadMessage(handle func(Message) error) error { msg, err := readMessageValue() if err != nil { return err } return handle(msg) }
Итог: сначала сделайте benchmark и pprof. Если аллокации действительно мешают, используйте value-структуру с полем
Typeи вложенными вариантами. Это безопаснее и проще, чем имитировать union через unsafe.