跳至内容
GitHub 代码库 论坛 RSS-新闻订阅

类型推断 (第一部分)

Brian J. Cardiff

类型推断是每个程序员都应该喜欢的功能。它让程序员无需在代码中指定类型,非常方便。

在这里,我们试图解释 Crystal 如何推断程序类型的基础。我们也希望对如何理解类型推断进行一些文档说明。

与大多数类型推断算法一样,解释是通过 AST 指导的。每个 AST 节点都将具有一个关联类型,该类型对应于表达式的类型。

整个程序 AST 被遍历,同时类型推断绑定 AST 节点,以模拟程序员为发现类型而做出的推断。

字面量

这些很简单。布尔值、数字、字符以及显式写入的值的类型由语法直接确定。

true # : Boolean
1    # : Int32

变量

编译器需要知道每个变量的类型。变量也有一个可以评估它们的上下文。

类型推断算法在每个上下文中注册存在的变量。因此,编译器将能够显式声明它们。

确定变量类型的最基本语句是赋值。

v = true

赋值的 AST 节点有 1) 目标 (左侧),2) 表达式 (右侧)。当确定 rhs 的类型时,类型推断算法指出 lhs 应该能够存储该类型的 value。

该算法不是以回溯方式进行计算 (为了支持更复杂的场景),而是通过在 AST 节点上构建依赖关系图来工作。

下一张图片显示了 AST 节点、保存变量和类型及其类型的上下文,以及突出显示各部分之间类型依赖关系的蓝色箭头。

条件语句 (也称为 if 语句)

Crystal 支持联合类型。当在同一个上下文中 (但在不同的分支中) 多次为变量赋值时,其预期类型是能够处理所有赋值的类型。因此,如果给出以下代码

if false
  v = false
else
  v = 2
end

在代码结束时,v 应该为 Int32 | Boolean 类型。

再次,我们展示了 AST 节点、保存变量和类型及其类型的上下文,以及突出显示各部分之间类型依赖关系的蓝色箭头。

当上下文中变量出现新类型时,会将其添加到“正在进行”的已知类型中。因此,出现了联合类型。

有一件事还没有显示出来。每个变量的出现都依赖于上下文。这将在下一张图片中显示

这样,每个赋值都知道它是为 Int32 | Boolean 赋值一个 Boolean 或为 Int32 | Boolean 赋值一个 Int32。此信息将在代码生成中使用。