6.7 TypeVar
1.最底层类型
如果Union内部无类型元素,即参数为空,Union{}便成了Julia中的另外一种特殊用法,用于表示类型系统中“最底层”的类型,即Union{}是所有类型的子类型,位于拓扑树的底部。例如:
julia> Union{} <: Int8 true julia> Union{} <: Real true julia> Union{} <: Char true julia> Union{} <: Any true julia> Union{} <: Type true
所以,Julia中的任意类型T均满足:Union{}<:T<:Any。如此一来,Julia的类型系统就构成了包含所有类型为元素的闭集。
需要注意的是,Julia中的Union{}是独立的类型,且其类型为Core.TypeofBottom,而不是DataType,即:
julia> typeof(Union{}) Core.TypeofBottom
不过Core.TypeofBottom的类型仍是DataType,即:
julia> typeof(Core.TypeofBottom) DataType
2.类型范围
如上所述,在Julia的类型系统中,Any是所有类型的父类型,位于类型拓扑树的顶部;而Union{}则是所有类型的子类型,位于拓扑树的底部。
前文曾提及,在类型拓扑图中,从任一类型节点到Any类型之间只存在唯一的路径,而且路径上的任意两个类型之间都存在父子关系。通过Union虽然可以取得一组类型组合,但需要逐一罗列才行。
不过,如果我们不需要跨路径的类型进行组合,而只需要同路径的诸多类型,是完全可以不必罗列的。Julia内部提供了一个TypeVar类型,用于表达某类型路径上一段范围的所有可选类型。其内部结构为:
TypeVar <: Any name::Symbol # Symbol类型后文介绍 lb::Any ub::Any
可见TypeVar有三个字段:其中name是类型变量的名称;成员lb限定了name的类型下界,即name必须是lb的父类型;ub则指定类型上界,即name必须是ub的子类型。
事实上,作为DataType实例的类型本身,TypeVar提供了一种对这些实例进行遍历的复合结构。其构造方法原型为:
TypeVar(name::Symbol, ub::ANY, lb::ANY) # 注意上界在下界之前,其中的::用于限定参数类型(后文介绍)
如果在构造时,其中的参数lb与ub省略,则表示不限定类型的上下界,此时这两个参数分别默认为Any和Union{},即:
julia> Union{} <: TypeVar(:T) <: Any true
如果要表达类型拓扑图中某段确切的类型范围,则可指定具体的类型作为上下界。例如:
julia> T = TypeVar(:T, Signed, Real) Signed<:T<:Real
表示类型T可以是Signed到Real中的任一类型,此时其内部结构为:
TypeVar name: Symbol T lb: Signed <: Integer ub: Real <: Number
一般来说,TypeVar会被Julia隐式地使用,开发者不需要显式地使用该类型。在我们对类型进行参数化时,这种结构便会由内部自动创建。下面会详细介绍类型参数化方法。