0
** Reason for termination =
** {badarg,[{erlang,'++',[<<>>,"</after></set></query></iq>"]},
            {geoloc,get_nearby,1},

方法是:

get_nearby({_Pid, DynVars})->
        %Last = ts_dynvars:lookup(last, DynVars),
        Last = lists:keysearch(last,1,DynVars),
        {ok, Rad} = ts_dynvars:lookup(rad,DynVars),
        {ok, Lat} = ts_dynvars:lookup(lat,DynVars),
        {ok, Lon} = ts_dynvars:lookup(lon,DynVars),
        if is_tuple(Last) ->
                {value,{Key,After}} = Last,
                if length(After) == 0 ->
                        After2 = "0";
                true ->
                        After2 = After
                end,
                "<iq id=\"" ++ common:get_random_string(5,"abcdefghijklmnopqrstuvwxyz0123456789-+=") ++ "\" xmlns=\"http://xmpp.xgate.com.hk/plugins\" to=\"xmpp.xgate.hk.com\" type=\"get\"><query xmlns=\"jabber:iq:geoloc\"><geoloc><lat>" ++ Lat ++ "</lat><lon>" ++ Lon ++ "</lon><radius>" ++ Rad ++ "</radius></geoloc><set xmlns=\"http://jabber.org/protocol/rsm\"><max>" ++ integer_to_list(ran_max()) ++ "</max><after>" ++ After2 ++ "</after></set></query></iq>";
        true ->         % Last is boolean, namely the 'false' atom
                ts_dynvars:set([rad, lat, lon], [Rad, Lat, Lon], DynVars),
                "<iq id=\"" ++ common:get_random_string(5,"abcdefghijklmnopqrstuvwxyz0123456789-+=") ++ "\" xmlns=\"http://xmpp.xgate.com.hk/plugins\" to=\"xmpp.xgate.hk.com\" type=\"get\"><query xmlns=\"jabber:iq:geoloc\"><geoloc><lat>" ++ Lat ++ "</lat><lon>" ++ Lon ++ "</lon><radius>" ++ Rad ++ "</radius></geoloc><set xmlns=\"http://jabber.org/protocol/rsm\"><max>" ++ integer_to_list(ran_max()) ++ "</max></set></query></iq>"
        end.
4

1 回答 1

5

您正在尝试连接二进制 ( <<>>) 和字符串,但++只能连接两个字符串(或列表 - Erlang 字符串实际上是列表)。

这意味着这After2是一个二进制文件,因此它在if表达式的第二个子句中接收到这个值。通常调用length(After)when Afteris not a list 会导致badarg异常,但当它出现在if测试中时,它会被视为警卫测试,异常会被忽略,因此length(After) == 0被视为 false。因此,当您将其放入时,相应的值已经是二进制文件DynVars

几点建议:

  • 要检查一个列表是否为空,调用它有点浪费length,因为length需要遍历整个列表。相反,请编写如下内容:

    case After of
        "" ->
            After2 = "0";
        [_|_] ->
            After2 = After
    end
    

    [_|_]是匹配非空列表的模式。在您的情况下,值After将不匹配任何子句,并且您会遇到一个case_clause错误,告诉您实际获得的值。

    当然,如果您真的希望这里有二进制文件,请检查<<>>and<<_/binary>>代替。

  • 你在++那里做了很多连接()。在表达式A ++ B中,++操作员需要沿着整个列表走入A,因此运行时间与 的长度成正比A

    连接有两种常见的替代方案。首先,通常会使用结果的函数实际上并不需要一个平面列表,但对“深度列表”或“iolist”同样满意——而不是"foo" ++ "bar", write ["foo", "bar"]。值得注意的是,如果您要将结果写入文件或将其发送到套接字,则两者都接受file:writegen_tcp:send接受这两种变体。

    其次,您可以使用二进制文件而不是字符串。二进制文件在许多有趣的方面与字符串不同(尤其是它们在垃圾收集方面的行为),但它们确实具有可以有效连接的良好特性。如果AB是二进制文件,并且您编写C = <<A/binary, B/binary>>,并且编译器可以看到您仅使用CA之后不使用,B则将简单地连接到保存的内存区域A。有关更多详细信息,请参阅《效率指南》中有关二进制处理的章节

  • 开头的两行"<iq id=\""几乎相同,只是第一行插入"<after>" ++ After2 ++ "</after>"到中间。您可以设置第一个 case 子句MaybeAfter = "<after>" ++ After2 ++ "</after>"和第二个 case 子句,然后在正确的位置MaybeAfter = ""插入一行的值。MaybeAfter这将有助于使代码更具可读性。

于 2013-08-26T01:42:14.563 回答