bson元组上的模式匹配

时间:2013-10-09 11:47:16

标签: erlang

bson-erlang module变成了BSON编码的JSON,如下所示:

{ "salutation" : "hello",
  "subject" : "world" }

进入像这样的Erlang元组:

{ salutation, <<"hello">>, subject, <<"world">> }

现在,我正在尝试与之交谈的服务器可以按任意顺序放置这些字段,并且可能还有其他字段,我不关心,所以 - 同样有效 - 我可能会看到这个:

{ subject, <<"world">>, salutation, <<"hello">>, reason, <<"nice day">> }

有没有什么方法可以指定一个函数模式来提取元组的特定部分,基于它之前出现的元组?

如果我尝试以下操作,它会因“没有函数子句匹配...”而失败,因为元组的arity是错误的,并且因为我关心的字段不在正确的位置:

handle({ salutation, Salutation, _, _ }) -> ok.

这可能吗?有更好的方法吗?

2 个答案:

答案 0 :(得分:0)

T = { subject, <<"world">>, salutation, <<"hello">>, reason, <<"nice day">> },
L = size(T),
L1 = [{element(I,T),element(I+1,T)} || I <- lists:seq(1,L,2)].

[{subject,<<"world">>},
 {salutation,<<"hello">>},
 {reason,<<"nice day">>}]

proplists:get_value(salutation,L1).                           
<<"hello">>

如果你想要1:

F = fun(Key,Tup) -> proplists:get_value(Key,[{element(I,Tup),element(I+1,Tup)} || I <- lists:seq(1,size(Tup),2)]) end.

F(reason,T).
<<"nice day">>
F(foo,T).
undefined

答案 1 :(得分:0)

在未知长度的前缀之后,没有模式成功匹配来自可变长度结构的值。对于元组,列表和二进制文件都是如此。实际上,这种模式需要通过结构进行递归。

列表的一种常见方法是通过分割头部和尾部来递归,这是典型的函数式语言。

f_list([salutation, Salutation | _]) -> {value, Salutation};
f_list([_Key, _Value | Tail]) -> f_list(Tail);
f_list([]) -> false.

请注意,如果列表包含奇数个元素,则此函数可能会失败。

使用元组可以采用相同的方法,但需要guards而不是匹配模式,因为没有模式可以提取元组尾部的等价物。实际上,元组不是链表,而是具有O(1)访问其元素(及其大小)的结构。

f_tuple(Tuple) -> f_tuple0(Tuple, 1).

f_tuple0(Tuple, N) when element(N, Tuple) =:= salutation ->
    {value, element(N + 1, Tuple)};
f_tuple0(Tuple, N) when tuple_size(Tuple) > N -> f_tuple0(Tuple, N + 2);
f_tuple0(_Tuple, _N) -> false.

同样,如果元组包含奇数个元素,则此函数可能会失败。

根据问题中的要素,警卫优于bson:at/2的优势尚不清楚。