关于在erlang中使用`||`

Bla*_*mba 2 erlang

我正在阅读项目的源代码recon,我发现了一个有趣的代码:

proc_attrs(binary_memory, Pid) ->
    case process_info(Pid, [binary, registered_name,
                            current_function, initial_call]) of
        [{_, Bins}, {registered_name,Name}, Init, Cur] ->
            {ok, {Pid, binary_memory(Bins), [Name || is_atom(Name)]++[Init, Cur]}};
        undefined ->
            {error, undefined}
    end;
Run Code Online (Sandbox Code Playgroud)

在这段代码中,有一个[Name || is_atom(Name)],

我试试shell:

27> [a || is_atom(a)].
[a]
28> [a || is_atom("a")].
[]
29> [a || true].
[a]
30> [a || false].
[]
Run Code Online (Sandbox Code Playgroud)

但我从来没有看到这样的用法,谁可以告诉我细节?

Ste*_*ski 6

[ ... || ... ]列表理解,通常用于在列表上操作以产生另一个列表.在这种情况下,仅使用理解的发生器侧(右侧)的滤波器部分作为条件,并且一如左侧仅在滤波器通过时产生值.考虑你的例子:

27> [a || is_atom(a)].
[a]
28> [a || is_atom("a")].
[]
Run Code Online (Sandbox Code Playgroud)

在命令27中,a确实是一个原子,因此过滤器is_atom/1通过,因此左侧产生值[a].但是在命令28中,is_atom/1过滤器消除了值,"a"因为它不是原子,左侧不产生任何值,因此结果是空列表.

这种方法是编写更长条件的简便方法.例如,您从recon引用的以下代码:

[Name || is_atom(Name)]++[Init, Cur]
Run Code Online (Sandbox Code Playgroud)

也可以写成:

case is_atom(Name) of true -> [Name]; false -> [] end ++ [Init, Cur]
Run Code Online (Sandbox Code Playgroud)

有人可能会说后者更容易理解,但显然它也更冗长,因此可能会使代码混乱太多.