4.2 类型与值
我们在前面提到了子类型(subtype)这个概念。与之相对的概念是超类型(supertype)。比如说,Integer
类型是Signed
类型的直接超类型,并且还是Int64
类型的间接超类型。如果用操作符<:
来表示的话,那就是:Int64 <: Signed <: Integer
。
实际上,Julia 中预定义的所有类型共同构成了一幅具有层次的类型图。这幅类型图中的类型之间都是有关系的。更具体地说,它们要么存在着直接或间接的继承关系,要么有着共同的超类型。
每一个 Julia 程序都会使用甚至定义一些类型。正因为如此,我们的程序才与 Julia 的类型系统关联在了一起。可以说,我们在编写程序时总会使用到 Julia 的类型图,并且有时候(即在自定义类型时)还会对这幅图进行扩展。我们定义的所有类型都会有一个超类型,即使我们没有显式地指定它。如此一来,我们的类型就与 Julia 原有的类型图联系在一起了。
我们之前说过,Julia 代码中的任何值都是有类型的。或者说,Julia 程序中的每一个值都分别是其所属类型的一个实例。不仅如此,每一个值也都分别是其所属类型的所有超类型的一个实例。例如:
julia> 10::Int64, 10::Signed, 10::Integer
(10, 10, 10)
julia>
可以看到,上例中的 3 个类型断言都成功了。也就是说,10
这个值既是Int64
类型的一个实例,也是Signed
类型和Integer
类型的一个实例。
此外,Julia 代码中所有的值都是对象(object)。但与那些传统的支持面向对象编程的语言不同,Julia 中的对象(或者说这些对象所属的类型)并不会包含或关联任何方法。恰恰相反,一个函数会用它的衍生方法去尽量适应被操作的对象。这正是由 Julia 的多重分派机制来控制的。
再次强调,Julia 中只有值才有类型,而变量本身是没有类型的。一个变量代表的只是一个标识符与某个值之间的绑定关系。