10

我正在编写代码来解码来自二进制协议的消息。每个消息类型都分配有一个 1 字节的类型标识符,并且每个消息都带有这个类型 id。消息都以由 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 个与上述类似的功能。我是否使用这种结构多次解码完整消息?是地道的吗?我最好只解码函数头中的消息类型字段,然后解码消息正文中的完整消息吗?

4

2 回答 2

8

只是同意你的风格是非常惯用的 Erlang。不要将解码分成单独的部分,除非您觉得它使您的代码更清晰。有时进行这种类型的分组可能更合乎逻辑。

编译器很聪明,它编译模式匹配的方式不会多次解码消息。它将首先解码前两个字段(字节),然后使用第二个字段的值(消息类型)来确定它将如何处理消息的其余部分。无论二进制文件的公共部分有多长,这都有效。

因此,他们无需尝试通过将解码拆分为单独的部分来“帮助”编译器,这不会提高效率。同样,仅当它使您的代码更清晰时才这样做。

于 2011-04-28T21:48:18.493 回答
7

您当前的方法是惯用的 Erlang,因此请继续朝这个方向发展。不用担心性能,Erlang 编译器在这里做得很好。如果您的消息格式完全相同,您可以为其编写宏,但它应该在引擎盖下生成相同的代码。无论如何,使用宏通常会导致更差的可维护性。只是出于好奇,为什么当所有记录类型都具有完全相同的字段时,您会生成不同的记录类型?另一种方法是将消息类型从常量转换为 Erlang atom 并将其存储在一种记录类型中。

于 2011-04-28T08:29:46.693 回答