Str*_*s3D 4 erlang types specifications header-files
Erlang 类型规范是否属于 .hrl 文件(这些文件被加载到任何需要它们的 .erl 文件中),或者应该将它们保存在 Erlang 模块中,然后导出(这将允许它们在其他模块中使用)?在我看来,这两种方法都可以实现相同的目标。
提前致谢!
类型规范(即-spec属性)属于定义函数的模块。时期。
另一方面,类型定义(-type、 )可以在文件中定义,但我认为这通常是一个糟糕的决定。这意味着,包含相关标头的每个模块都将在本地“定义”类型。当模块已经定义了一个类型,而该类型也在您想要包含的标头中定义时,这可能会导致命名空间冲突。从模块导出类型而不是在s 中定义它们会为您提供名称空间前缀,并消除本地定义的类型 ( ) 和外部应用程序/模块定义的类型 (或者,原文如此!,) 之间的歧义。-opaque.hrl.hrlmytype()yourmod:yourtype()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())定义和导出类型。
特科瓦尔提出的观点也很重要。如果您不想公开内部结构,那么该-opaque属性就是为了做到这一点 - 它表示“不依赖于该类型的内部结构”。因此,您只需要定义一个类型而-opaque不是-type,将其导出,然后让 Dialyzer 警告您代码中意外构建该类型术语但未明确声明的每个位置,或者警告您尝试尝试的每个模式匹配。在定义该类型的模块外部解构该类型。