Erlang шаблон, соответствующий цепочке битов - PullRequest
10 голосов
/ 28 апреля 2011

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

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

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

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 функций, аналогичных описанным выше. Я декодирую полное сообщение несколько раз с этой структурой? Это идиоматично? Не лучше ли мне просто декодировать поле типа сообщения в заголовке функции, а затем декодировать полное сообщение в теле сообщения?

Ответы [ 2 ]

8 голосов
/ 29 апреля 2011

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

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

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

7 голосов
/ 28 апреля 2011

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

...