让我们先回顾一下您的问题,因为我们可以做出一些误解和/或更正。
你的描述
尽管似乎可以工作,但该程序正在崩溃。我不明白为什么。我正在尝试完成深度合并并需要条件逻辑。
给定以下列表:
ManOne = #{ "Bob" => #{"Sagget" => #{}} }
ManTwo = #{ "Bob" => #{"Daniels" => #{}} }
请注意,以上不是列表,它们是地图,其功能完全不同。
出于所有意图和目的,映射是一个查找表,直到它包含约 31 个键/值对。
此时,它变成了一个HashMap(这可以通过查看元素在map变成一个HashMap后变得无序来看到)。
我试图将它们进行如下比较,此函数按预期返回 true:
check_if_same(M1, M2) ->
{ok, lists:sort( maps:keys(M1) ) == lists:sort( maps:keys(M2) )}.
这是断言平等的错误方式;在 erlang 中,建议不要使用==
检查相等性。
相反,=:=
应该使用。
这样做的原因是因为==
它不检查它正在比较的元素的类型并且只取一个模糊值 -1 == 1.0
即将返回 true 但1 =:= 1.0
将返回 false。
就个人而言,我建议改为使用 Erlang 的模式匹配来检查您的值。
这可以使用以下代码片段来实现:
-spec check_if_same(M1 :: map(), M2 :: map()) -> boolean().
check_if_same(M1, M2) ->
SortedKeys1 = lists:sort(maps:keys(M1)),
SortedKeys2 = lists:sort(maps:keys(M2)),
%% We hide the implementation of the function in
%% a function with the same name suffixed with an
%% underscore. This allows us to have a public api
%% but keep the implementation internal which allows
%% the code to be a bit cleaner.
check_if_same_(SortedKeys1, SortedKeys2).
%% If they're both empty then we've gone through
%% every key meaning that they must be identical
check_if_same_([], []) ->
true;
%% If the current Key on both heads is the same
%% then recurse and check the next and so on
check_if_same_([Key|Tail1], [Key|Tail2]) ->
check_if_same_(Tail1, Tail2);
%% If we get anything else, e.g more keys in
%% one than the other or the keys don't match,
%% then we'll fall in to this case.
%% As we know anything that falls in to this
%% case doesn't match, we just return false
check_if_same_(Keys1, Keys2) when is_list(Keys1), is_list(Keys2) ->
false.
请注意,在上面的代码段中,我只返回过true
或者false
- 我对更简洁代码的建议是保持以下格式;
ok
- 这通常适用于您关心效果而不是返回的功能
true
| false
- 这通常用于比较函数,is_binary/1
即is_function/1
{ok, Value}
- 这通常适用于您关心返回值的任何函数
{error, Reason}
- 这将在您预期出现错误时使用,以便您可以使用易于匹配的格式将错误冒泡备份到链中
你的代码片段
merger(M1, M2) ->
M1_Keys = maps:keys(M1),
%% Note that you don't use the M2Keys here so you don't need to do the work to get them
M2_Keys = maps:keys(M2),
do_merge(M1, M2, M1_Keys).
do_merge(M1, M2, [Head|Tail]) ->
Check = check_if_same(M1, M2),
%% It's generally recommended to stick to io:format/2 rather than io:fwrite/2
io:fwrite("Check is: ~p\n", [Check]),
case Check of
{ok, true} ->
io:fwrite("true\n");
{ok, false} ->
io:fwrite("false\n")
end,
do_merge(M1, M2, Tail);
do_merge(M1, M2, []) ->
ok.
check_if_same(M1, M2) ->
{ok, lists:sort( maps:keys(M1) ) == lists:sort( maps:keys(M2) )}.
现在,上面的代码片段(除了效率有点低)完全可以 erlang 并且可以按预期工作
给出以下输出:
Check is: {ok,true}
true
{"init terminating in do_boot",{{badmap,ok},[{maps,keys,[ok],[]},{helloworld,merger,2,[{file,"helloworld.erl"},{line,9}]},{init,start_em,1,[]},{init,do_boot,3,[]}]}}
init terminating in do_boot ()
Crash dump is being written to: erl_crash.dump...done
这个故障转储是真正的问题所在;
Check is: {ok,true}
true
由此我们可以看出我们
- 点击 io:fwrite/2 (
io:fwrite("Check is: ~p\n", [Check])
)
- 输入case ( )
{ok, true}
中的路径io:fwrite("true\n")
下一行是我们看到实际问题的地方,让我们分解一下:
"init terminating in do_boot"
- 启动时失败,这可能是在运行 escript 或启动应用程序时
现在让我们分解那个元组:
{
{badmap,ok}, %% The function we called expected a map and we passed in 'ok'
[
{maps,keys,[ok],[]}, %% We called maps:keys/1 with 'ok' as an arg
{helloworld,merger,2,[{file,"helloworld.erl"},{line,9}]}, %% This was called at helloworld:merger/2 (helloworld.erl:9)
{init,start_em,1,[]},{init,do_boot,3,[]} %% We failed on start up
]
}
我们可以从中得出的结论是,您在代码中使用helloworld.erlok
的第9 行的无效值调用合并