** 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.
答案 0 :(得分:5)
您正在尝试连接二进制文件(<<>>
)和字符串,但++
只能连接两个字符串(或列表 - Erlang字符串实际上是列表)。
这意味着After2
是二进制文件,因此它在if
表达式的第二个子句中接收到此值。通常在length(After)
不是列表时调用After
会导致badarg
异常,但是当它出现在if
测试中时,它会被视为保护测试,并忽略异常,因此length(After) == 0
被视为假。因此,当您在DynVars
中获得相应的值时,相应的值已经是二进制值。
一些建议:
要检查列表是否为空,在其上调用length
有点浪费,因为length
需要遍历整个列表。相反,写下类似的东西:
case After of
"" ->
After2 = "0";
[_|_] ->
After2 = After
end
[_|_]
是一种匹配非空列表的模式。在您的情况下,After
的值与任何子句都不匹配,并且您有一个case_clause
错误,告诉您实际得到的值。
当然,如果你真的希望在这里使用二进制文件,请检查<<>>
和<<_/binary>>
。
你在那里进行了很多连接(++
)。在表达式A ++ B
中,++
运算符需要遍历A
中的整个列表,因此运行时间与A
的长度成正比。
连接有两种常见的替代方法。首先,通常会消耗结果的函数实际上不需要平面列表,但对“深度列表”或“iolist”同样满意 - 而不是"foo" ++ "bar"
,写["foo", "bar"]
。值得注意的是,如果您要将结果写入文件或将其发送到套接字,则file:write
和gen_tcp:send
都接受这两种变体。
其次,您可以使用二进制文件而不是字符串。二进制文件在许多有趣的方面与字符串不同(至少它们在垃圾收集方面的表现如何),但它们确实具有可以有效连接的良好属性。如果A
和B
是二进制文件,并且您编写C = <<A/binary, B/binary>>
,并且编译器可以看到您之后仅使用C
而不是A
,{{{ 1}}将简单地连接到保留B
的内存区域。有关详细信息,请参阅the chapter on binary handling in the Efficiency Guide。
以A
开头的两行几乎完全相同,只是第一行在中间插入"<iq id=\""
。您可以将第一个case子句设置为"<after>" ++ After2 ++ "</after>"
,将第二个case子句设置为MaybeAfter = "<after>" ++ After2 ++ "</after>"
,然后使用一行在正确的位置插入MaybeAfter = ""
的值。这将有助于使代码更具可读性。