如何将类型记录为名称?

How to document a type as just a name?

查看 Erlang 文档,有时我会遇到类型规范,它记录了一个函数类型而没有真正指定类型...

很难解释,所以让我给你一个example。在 gen_server 中,handle_call 函数在文档中显示如下:

Request = term()
From = {pid(),Tag}
State = term()
Result = {reply,Reply,NewState} | {reply,Reply,NewState,Timeout}
  | {reply,Reply,NewState,hibernate}
  | {noreply,NewState} | {noreply,NewState,Timeout}
  | {noreply,NewState,hibernate}
  | {stop,Reason,Reply,NewState} | {stop,Reason,NewState}
 Reply = term()
 NewState = term()
 Timeout = int()>=0 | infinity
 Reason = term()

这里从未显示类型 Tag(即它只是一个变量名)。

是否可以用edoc做同样的事情?我找到的最接近的是不透明类型规范,但将其记录为 abstract - 是一样的吗?

据我所知,Edoc 无法做到这一点。

我试过使用这样的规范:

-spec foo(Something) -> term().
foo(X) ->
    X.

虽然 Edoc 实际上对此很满意,并在文档中将类型规范指定为 foo(Something),但没有指定 Something 是什么,但编译器对此表示不满,并说:

type variable 'Something' is only used once (is unbound)

所以你必须写:

-spec foo(Something::_) -> term().
foo(X) ->
    X.

显示为 foo(Something::term()),从而给出了 Something.

的类型规范

使用 Edoc-only 类型规范:

%% @spec foo(Something) -> term()
foo(X) ->
    X.

Edoc 将 Something 视为应用于变量 X 的类型名称,并将 foo(X::Something) 放入文档中。

所以这两种方法都不能完全达到您想要的效果。

只要函数中的参数变量名称(在所有子句中)与 @spec 中使用的名称相同即可。例如。

%% @spec start_link(Args) -> {ok, pid()}
start_link(Args) ->
    gen_server:start_link(?MODULE, Args, []).

将生成以下文档

start_link(Args) -> {ok, pid()}

如果您有不同的名字,例如

%% @spec start_link(Args) -> {ok, pid()}
start_link(Num) when is_integer(Num) ->
    gen_server:start_link(?MODULE, [], []);
start_link(Args) ->
    gen_server:start_link(?MODULE, Args, []).

它将生成为

start_link(Num::Args) -> {ok, pid()}

假设 Args 是一个类型。

我个人不建议使用 edoc @spec,而是使用 -spec,因为它们被 dialyzer 使用,因此可以被验证。

edoc 也可以从 -spec 生成文档。给定 -spec 和 @spec,edoc 覆盖 @spec 指令。

%% @spec start_link(Args) -> {ok, Pid}
-spec start_link(term()) -> {ok, pid()}.
start_link(Args) ->
    gen_server:start_link(?MODULE, Args, []).

以上将导致

start_link(Args) -> {ok, Pid}

从上面删除@spec 将导致

start_link(Args::term()) -> {ok, pid()}