如何使用erlang fun递归函数?

问题描述 投票:1回答:2

我正在尝试解码具有可变长度和选项的帧(例如以太网帧中的TLV)为了做到这一点,我正在考虑做一个有趣的递归函数:

fun (Fields, Bin) ->
    Parse =
        fun (P, F, <<Length, Rest/binary>>) ->
                P(P, F#{first => Length}, Rest)
        end,
    Parse(Parse, Fields, Bin)
end.

所以Bin是输入帧,例如:40 02 12 45 01 50所以第一个字节是帧的类型,02是跟随数据12 45的长度,01的长度是以下数据50等等。

但是我的功能并没有像预期的那样使用有趣的技巧

我正在返回JSON对象,因为它是通过MQTT发送的。

recursion erlang frame
2个回答
1
投票

你在那里做的事情实际上只是读出长度,并且对Rest做的不多。你需要先声明一个退出条件,即当TLV为空时 - >只返回累加器;并使用模式匹配来读取基于Length的值:

parse(<<>>, Acc) -> Acc;  %% finished with the list
parse(<<Length, Rest/binary>>, Acc) ->
   <<Value:Length/binary, Carry/binary>> = Rest.
   %% Value for the tag, Carry to be passed back on the recursion.
   %% Assuming that `Acc` is a list of Values.
   parse(Carry, Acc ++ [Value]).

您可以使用上面的内容来读取值,并可以执行类似的操作以获取类型:

tlv(<<Type, Values/binary>>) ->
   %% Return at tuple with the Type and the values.
   {Type, parse(Values, [])}.

0
投票

你可以写这样的函数:

fun(<<Type, Packet/binary>>) ->
        {Type,
         fun Parse(<<>>) ->
                 [];
             Parse(<<Length, Data:Length/bytes, Rest/binary>>) ->
                 [Data] ++ Parse(Rest)
         end(Packet)}
end.

这将返回{40,[<<12,45>>,<<50>>]}作为样本数据。

外部乐趣采用帧类型(在这种情况下为40),并将其与数据字段列表一起返回。内部乐趣需要一个长度字节和相应数量的数据字节,并返回数据并对其自身进行递归调用 - 直到它到达二进制文件的末尾。

内在的乐趣是“命名的乐趣”:它自称为Parse,因此能够自称,而不需要将自己作为一个参数。名字Parse在乐趣之外是不可见的。有关详细信息和示例,请参阅this question

© www.soinside.com 2019 - 2024. All rights reserved.