Erlang中是否有与C预处理器指令##相同的东西?
假设我想使用-define预处理器指令连接两个atom(),如何在没有运行时副作用的情况下执行?
答案 0 :(得分:4)
您可以使用解析转换获得足够接近的结果。以下parse_transform查找“atom1 ++ atom2”并在编译时将其转换为“atom1atom2”。
示例模块
-module(z).
-export([z/0]).
-compile({parse_transform, zt}).
z() -> concat ++ enate.
使用'S'进行编译证明它在编译时确实连接在一起:
{function, z, 0, 2}.
{label,1}.
{func_info,{atom,z},{atom,z},0}.
{label,2}.
{move,{atom,concatenate},{x,0}}.
return.
按预期工作:
1> z:z().
concatenate
包含解析变换的模块:
-module(zt).
-export([parse_transform/2]).
parse_transform(AST, _Options) ->
[parse(T) || T <- AST].
parse({function, _, _, _, _} = T) ->
erl_syntax_lib:map(fun hashhash/1, T);
parse(T) -> T.
hashhash(Tree) ->
erl_syntax:revert(
case erl_syntax:type(Tree) of
infix_expr ->
Op = erl_syntax:infix_expr_operator(Tree),
Left = erl_syntax:infix_expr_left(Tree),
Right = erl_syntax:infix_expr_right(Tree),
case {erl_syntax:operator_name(Op), erl_syntax:type(Left), erl_syntax:type(Right)} of
{'++', atom, atom} ->
erl_syntax:atom(erl_syntax:atom_literal(Left) ++ erl_syntax:atom_literal(Right));
_ ->
Tree
end;
_ ->
Tree
end
).
编辑:编辑为“重载”infix ++运算符。以前的版本使用'##'功能。
答案 1 :(得分:1)
我不确定我明白你在问什么,但我会捅它。
-define(CATATOM(A, B), list_to_atom(list:concat(atom_to_list(A), atom_to_list(B)))).
AtomA = atom1.
AtomB = atom2.
NewAtom = ?CATATOM(AtomA, AtomB). % NewAtom is atom1atom2
或者你的意思是这个?
-define(CATATOM(A, B), AB).
NewAtom = ?CATATOM(atom1, atom2). % NewAtom is atom1atom2
虽然我不确定新的第二个实际上是什么用途。因为只编写atom1atom2而不是宏来简单。
第二个不会产生运行时副作用。第一个会产生运行时副作用,因为宏的结果是在运行时运行的3个函数。
答案 2 :(得分:1)
你实际上不能在宏中做任何事情,它只是纯文本,良好的令牌级别,替换。注:您正在处理源代码而不是评估它。如果您需要更复杂的替换类型,则需要使用解析转换。
如果你编写一个连接宏,你总是可以使用?? Arg形式将参数作为字符串。查看在线参考手册的预处理器部分。
当然,真正有趣的问题是为什么你想在编译时连接两个原子?我假设它是另一个宏的输出,否则就没有意义了。
答案 3 :(得分:0)
我认为没有。我认为,因为你可以在运行时做任何这些东西没有副作用
答案 4 :(得分:0)
有一个解析变换的概念,它允许你在编译时连接原子。
答案 5 :(得分:0)