类型规范可以说明函数预期的输入类型和返回类型。有些编程语言的编译器使用类型规范来优化代码并检查正确性。Elixir是动态语言,它的编译器不会用类型规范来优化代码。但是,可以使用dialyzer工具借助类型规范做静态检查,从而发现潜在错误。类型规范也有利于生成文档。我们将运用类型规范改进DungeonCrawl.Room.Trigger.run/2契约。
DungeonCrawl.Room.Trigger.run/2需要一个角色和一个房间动作。我们要创建角色和房间类型。然后我们可以指定run/2函数的参数。让我们在lib/dungeon_crawl/character.ex中定义角色类型,请添加以下代码:
我们使用@type指令开始类型定义。该类型的名称为t,::之后的代码是类型定义。这个类型是DungeonCrawl.Character结构体,它由具有指定类型的属性组成。有些类型可以用简单的名字引用,比如Integer。而String类型必须使用模块的t函数来访问。在Elixir中,使用t定义结构体类型是一种常见的做法。类型规范清楚地说明了结构体的每个属性。接下来定义动作的类型规范:
房间的id是一个原子,label是一个字符串。最后,通过关联我们创建的类型来改进run/2规范:
第一个参数要求一个角色类型,第二个参数要求一个动作类型。该函数应返回一个元组,其中第一项是角色类型,第二项是原子。修改后,run/2的参数和返回值有了明确的规定。
类型规范还可以帮助静态分析工具发现错误,比如,因传递错误类型而无法调用的函数。使用静态分析工具Dialyzer,先要安装dialyxir库。[5]
安装Dialyxir需要为应用程序添加一个库。Mix提供了简单的方法。我们只需要更新mix.exs文件,然后运行一些Mix任务。用以下代码更新mix.exs:(www.xing528.com)
在deps函数中,我们必须返回一个元组列表。第一项是库的名称,第二项是版本,第三项是可选的关键字列表选项。我们指明需要dialyxir库,版本大于0.5.0,只需要在dev环境中使用。版本方案遵循语义化版本。[6]现在我们要运行任务下载和编译新库。Mix任务将从Hex下载库。[7]运行如下命令:
我们用mix do运行了两个任务,deps.get下载依赖项,而后deps.compile进行编译。然后,我们就可以在终端中运行dialyzer任务了。第一次运行会花较长时间,因为它要分析Elixir的所有库,然后检查你的代码。以后再运行就会快很多。运行试试:
运行一段时间后,你会看到dialyzer警告Mix缺失函数。注意,如果你没有删除协议DungeonCrawl.DungeonCrawl.Display,可能会看到缺少协议实现的警告。你可以删除协议,或者忽略警告,因为协议实现不是必需的。要解决这个
问题,只需要告诉dialyzer在分析中包含Mix,像这样:
再次运行dialyzer,警告消失了。如果你想查看代码执行效果,请将DungeonCrawl.Room.Trigger.Exit的返回值从原子改为字符串。然后再次运行,它会显示类似于如下的输出:
Dialyzer会警告run/2函数不符合Elixir.DungeonCrawl.Room.Trigger行为。类型规范可以帮助Dialyzer发现错误。对类型规范感兴趣的读者,可以查阅Elixir的官方文档。[8]接下来,我们要给游戏增加一点难度。
免责声明:以上内容源自网络,版权归原作者所有,如有侵犯您的原创版权请告知,我们将尽快删除相关内容。