还记得吗?我们在前面定义第一个sum1函数的时候,并没有为它的两个参数指定类型。然而,在这种情况下,这两个参数实际上都会有一个缺省的类型,即:Any类型。这也是为什么我们可以用任何类型的值作为参数值调用这个sum1函数的原因。

    再比如,我们可以定义如下的原语类型(我们稍后会讲到这种类型):

    注意,我们没有显式地指定它的超类型。然而,在这种情况下,MyWord类型会有一个缺省的超类型,同样是Any类型。也就是说,这个MyWord类型是Any类型的直接子类型。

    4.3.2 Union{} 类型

    在 Julia 的类型图中,还有一个与完全相对的类型。它就是Union{}类型。由于这个类型是所有类型的子类型,所以它是一个底层类型,并且也是唯一的一个。它处在类型图的最底端。也就是说,对于任意类型的变量x,类型断言x::Union{}都必定是失败的。另外,与Any一样,Union{}也是一个抽象类型。

    从字面上我们就可以看出,Union{}是一个被参数化的类型。它的源类型是Union{Types...}类型,其中的Types...代表任意个类型参数。如果这里有多个类型参数,那么它们之间需要用英文逗号分隔开。

    这个Union{Types...}类型有着一种很特殊的用途。我们可以利用它,让一个单一的类型字面量代表多个类型。换句话说,把多个类型联合在一起形成一个类型,并让后者作为前者的统一代表。因此,我们也可以把这个类型称为联合类型。而每一个类型参数的组合都可以代表一种联合类型。示例如下:

    另外,由于 Julia 中的类型属于一类特殊的值(DataType类型的值),所以上述的联合类型自然也就可以与标识符IntOrString绑定在一起。这时,我们可以说IntOrString是那个联合类型的别名(alias)。

    搞清楚了联合类型以及它的用途,我们就很容易理解“Union{}类型处在类型图的最底端”的原因了。由于它的花括号中没有任何类型参数,所以这种联合类型也就代表不了任何类型,相当于一个“虚无”的类型。而任何类型都比“虚无”包含了更多的东西,所以它们都是这种联合类型的超类型。如果我们使用操作符<:在这些类型之间做判断的话,就可以很形象地看到这种关系:

    此示例中的两个表达式的结果值都是true。这说明整数类型Integer和联合类型Union{Integer}都是“虚无”类型Union{}的超类型。