类型规格属于.hrl文件吗?

时间:2014-09-18 22:31:58

标签: types erlang header-files specifications

Erlang类型规范是否属于.hrl文件(它们被加载到任何需要它们的.erl文件中),或者它们应该保存在Erlang模块中,然后导出(这将允许它们在其他模块中使用) ?在我看来,这两种方法都可以实现同样的目的。

  • 我遗失了哪些微妙的差异? (我知道头文件的内容被复制到每个使用它们的文件中,基本上是在编译时复制代码。)
  • 是否有时候应该使用一种方法而不是另一种方法?

提前致谢!

3 个答案:

答案 0 :(得分:3)

类型规范(即-spec属性)属于定义函数的模块。周期。

另一方面,类型定义(-type-opaque)可以在.hrl文件中定义,但我认为这通常是一个糟糕的决定。这意味着,包含所讨论的标题的每个模块都将定义"本地的类型。当模块已经定义了一个类型时,这可能会导致名称空间冲突,该类型也在您想要包含的标题中定义。 从模块导出类型而不是在.hrl中定义它们会为您提供名称空间前缀,并在本地定义的类型(mytype())和外部应用程序/模块(yourmod:yourtype()或sic!)之间消除歧义。 yourmod:mytype())。

通常,在编写Erlang应用程序或库时,最好定义使用它的模块中的类型(最多)。对于在库外导出的类型,从主库模块中导出它们 - 如果应用程序名为myapp,则可以访问所有公共类型,如myapp:config()myapp:some_record()

我还想到了另一件事:Dialyzer不喜欢简单的记录定义 - 建议明确定义记录的类型(因此每个-type只有一个-record) 。另一方面,将记录定义放在头文件中很方便,因此可以在不同位置的代码(例如src/mymod.erltest/mymod_tests.erl)之间共享它们。在这种情况下,我在头文件中定义记录(src/mymod.hrl用于私有模块,如果模块是应用程序/库公共接口的一部分,则include/mymod.hrl,但仍然定义和导出它所属模块的类型(即mymod:some_record())。

提出的tkowal点也很重要。如果您不想公开内部结构,那么-opaque属性就是为了做到这一点 - 它说“不要依赖于这种类型的内部结构和&#34} #34 ;.因此,您只需要使用-opaque而不是-type定义类型,然后将其导出,让Dialyzer警告您代码中的每个位置,这些位置意外地构建了该类型的术语但不是明确说明,或者说每个模式匹配,它试图在定义类型的模块之外解构该类型。

答案 1 :(得分:2)

实际上,使用edoc应用程序生成函数/模块文档的规范确实很重要。

如果正确的规范条款不在正确的功能条款之上,edoc会抱怨并且整个模块的文档生成将失败。

请想一想edoc。

答案 2 :(得分:1)

这并不重要。你可以把它们放在合理的地方。

  • 如果您的类型与记录定义紧密相关,并且应该知道它们的内部结构 - 将它们放在.hrl文件中。
  • 如果您不想公开内部结构(例如,您使用了proplists,但是您希望将来更改为dicts),则最好使用访问器函数创建模块并将类型规范放在那里并附带注释:“不依赖于这种类型的内部结构”。您仍然希望将其导出以确保其他模块使用它。甚至,如果他们将它用作黑匣子。

如果你把东西放在.hrl中,其他模块依赖它 - 它就更难改变。当你把它放在模块中时,它应该更容易修改和重构。