Соответствующие биты строк Erlang

Я пишу код для декодирования сообщений из двоичного протокола. Каждому типу сообщения присваивается идентификатор 1 байтового типа, и каждое сообщение содержит этот идентификатор типа. Все сообщения начинаются с общего заголовка, состоящего из 5 полей. Мой API прост:

decoder:decode(Bin :: binary()) -> my_message_type() | {error, binary()}`

Мой первый инстинкт состоит в том, чтобы сильно наклониться на соответствие шаблонов, написав одну функцию декодирования для каждого типа сообщения и полностью декодировать этот тип сообщения в аргументе fun

decode(<<Hdr1:8, ?MESSAGE_TYPE_ID_X:8, Hdr3:8, Hdr4:8, Hdr5:32, 
         TypeXField1:32, TypeXFld2:32, TypeXFld3:32>>) ->
    #message_x{hdr1=Hdr1, hdr3=Hdr3 ... fld4=TypeXFld3};

decode(<<Hdr1:8, ?MESSAGE_TYPE_ID_Y:8, Hdr3:8, Hdr4:8, Hdr5:32, 
         TypeYField1:32, TypeYFld2:16, TypeYFld3:4, TypeYFld4:32
         TypeYFld5:64>>) ->
    #message_y{hdr1=Hdr1, hdr3=Hdr3 ... fld5=TypeYFld5}.

Обратите внимание, что хотя первые 5 полей сообщений структурно идентичны, поля после этого изменяются для каждого типа сообщения.

У меня примерно 20 типов сообщений и, следовательно, 20 функций, подобных описанным выше. Я несколько раз расшифровываю полное сообщение с этой структурой? Это идиоматично? Не лучше ли мне просто декодировать поле типа сообщения в заголовке функции, а затем декодировать полное сообщение в теле сообщения?

Ответ 1

Просто чтобы согласиться, что ваш стиль очень идиоматический Эрланг. Не разделяйте декодирование на отдельные части, если только вы не чувствуете, что он делает ваш код более четким. Иногда логичнее делать такой тип группировки.

Компилятор является интеллектуальным и компилирует соответствие шаблонов таким образом, что он не будет декодировать сообщение более одного раза. Сначала он будет декодировать первые два поля (байты), а затем использовать значение второго поля, тип сообщения, чтобы определить, как он будет обрабатывать остальную часть сообщения. Это работает независимо от того, как долго общая часть двоичного файла.

Поэтому им не нужно пытаться "помочь" компилятору, разделив декодирование на отдельные части, это не сделает его более эффективным. Опять же, только сделайте это, если это сделает ваш код более ясным.

Ответ 2

Ваш текущий подход - идиоматический Эрланг, поэтому продолжайте двигаться в этом направлении. Не беспокойтесь о производительности, компилятор Erlang неплохо работает здесь. Если ваши сообщения в точности соответствуют одному и тому же формату, вы можете написать макрос для него, но он должен генерировать одинаковый код под капотом. В любом случае использование макроса обычно приводит к ухудшению ремонтопригодности. Просто для любопытства, почему вы создаете разные типы записей, когда все имеют одинаковые поля? Альтернативный подход - это просто перевести тип сообщения с константы на атом Эрланга и сохранить его в одном типе записи.