功能规格:-spec。有效使用

时间:2012-02-21 13:54:19

标签: erlang

我如何在erlang中使用-spec字? 请给我一个有效使用这个词的想法。这仅代表文档目的吗?

我尝试使用-spec按功能类型规范在模块中应用约束,但我失败了 - 没有应用任何限制。

2 个答案:

答案 0 :(得分:18)

-spec属性确实被编译器和运行时系统视为文档。您无法使用它们向代码中添加任何“可执行功能”,这同样适用于-type-opaque属性。

然而,它们非常有用:

  • 文档:EDoc使用它们为您的代码生成所有不同形式的文档。 -spec属性是函数签名,根据您投入的精力,可以使您的代码更易于理解和维护。假设本月您最喜欢的数据结构是dict()。请考虑以下代码:

    my_function(SomeArg, SomeOtherArg, Dict) ->
      ...
      dict:find(SomeKey, Dict)
      ...
    

    用作dict的变量已被命名为。但是,假设您有以下代码段:

    my_other_function(NamesDict, PlacesDict) ->
      ...
      R1 = my_function(A, B, NamesDict),
      ...
      R2 = my_function(C, D, PlacesDict),
    ...
    

    尝试跟上这一点可能很快会导致代码重复此Dict后缀。更甚事,您甚至可能不想在my_other_function的上下文中记住这两个参数是dict()。所以你可能想要这样做:

    -spec my_other_function(dict(), dict()) -> atom().
    
    my_other_function(Names, Places) ->
      ...
      R1 = my_function(A, B, Names),
      ...
      R2 = my_function(C, D, Places),
      ...
    

    现在很明显,这些参数应该是dict()才能使函数正常工作,并希望每个人都能够在不深入代码的情况下解决这个问题。但是假设您在其他地方使用此Name dict()并且它存储了使用不同API公开的某些特定信息。然后它是-type声明的完美候选者:

    -type names() :: dict().
    
    -spec my_other_function(names(), places()) -> atom().
    
    my_other_function(Names, Places) ->
      ...
      R1 = my_function(A, B, Names),
      ...
      R2 = my_function(C, D, Places),
      ...
    

    如果其他人频繁使用此特定数据结构,您可能也想要将其导出:

    -module(my_module).
    
    -export_type([names/0]).
    
    -type names() :: dict().
    

    其他模块现在可以引用这个特定的数据结构:

    -module(my_other_module).
    
    -record(my_state, {names :: my_module:names(),
                       ...}).
    

    最后,如果您希望其他开发人员不在其模块中以任何方式检查此数据结构,则可以将其声明为-opaque。同样,这是一个“友好的建议”,就像到目前为止所有其他的东西一样。或者是......?

  • 差异检测:如果您花时间使用-specs-types,您会非常希望这些内容保持最新。众所周知,如果没有观看,没有人保持文档最新!幸运的是, Dialyzer 正在观看。透析器可以 check在所有调用my_function()的参数都是dict()(即使没有-spec注释,它也可以执行此操作,但它更容易如果你也有这些话,并且如果你用其他东西称呼它就会尖叫血腥谋杀。此外,它还可以跟踪这些导出的类型,甚至可以报告不透明度违规。所以它不仅仅是“文档”。

  • 测试用法生成支持者可以使用-spec-type定义通过随机测试用例自动检查您的功能。它甚至可以从像这样的声明中创建随机测试用例:

    -type int_tree() :: {node, integer(), tree(), tree()} | nil.
    
  • 为行为指定一组回调的全新方式是使用熟悉的-spec语法。编译器,Dialyzer和其他可能的工具可以使用此信息来检查行为实现。请参阅OTP行为codehere

  • 中的更多内容

了解更多here

答案 1 :(得分:8)

-spec的功能是规范,它们有几个地方可以提供帮助:

  • 它们充当函数的文档。生成EDoc将提取规范并在文档中提供它们。
  • 它们是透析器的规格。当透析器运行时,它将使用规范以任何方式确定代码是否错误。也就是说,如果您的规范是错误的 - 在某些情况下,它将帮助系统准确理解代码错误的原因。
  • 它们是行为规范中的宝贵工具。有一个新的-callback关键字可用于为行为API执行此操作。
  • 它们对于构建程序如何组合以及数据来源的类型框架非常有用。
  • 与堂兄-type-opaque一起,您可以强制某些类型对代码段不透明。这意味着您不能在静态验证级别上查看内部表示。这可以反过来帮助驱动模块化代码,因为您不允许紧密地耦合代码片段。