Erlang类型规范是否属于.hrl文件(它们被加载到任何需要它们的.erl文件中),或者它们应该保存在Erlang模块中,然后导出(这将允许它们在其他模块中使用) ?在我看来,这两种方法都可以实现同样的目的。
提前致谢!
答案 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.erl
和test/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中,其他模块依赖它 - 它就更难改变。当你把它放在模块中时,它应该更容易修改和重构。