Julia协变与逆变

Julia协变与逆变,事实上,Julia还提供了另外一种参数类型具象化的方式,即协变Covariant)与逆变Contravariant),基本用法分别为:

类型名{ <: 类参值}
类型名{ >: 类参值}

下面我们以无限界版的参数抽象类型Pointy为例,具体解释这两者的概念与区别(其他类型相似)。

假设以协变形式对Pointy进行具象化,即:

julia> Pointy{<:Integer}
  Pointy{#s1} where #s1<:Integer

可以发现,得到的是带有where关键字的具象类型。查看其内部结构,如下:

UnionAll
  var: TypeVar
    name: Symbol #s1
    lb: Core.TypeofBottom Union{}
    ub: Integer <: Real
  body: Pointy{#s1<:Integer} <: Any

可见这一具象化类型是一个典型的UnionAll结构,只不过因为未提供特定的类参符号,所以内部自动创建了#s1类型参数。实际上,我们也可以显式地使用where方式声明这样的结构,例如:

julia> Pointy{T} where {T<:Integer}
Pointy{T} where T<:Integer

可见,得到的形式与Pointy{<:Integer}完全相同;逆变情况与上述类似,不再单独示例。

在使用where关键字创建协变或逆变对象时,语法类似于:

类型名{T1, T2, …} where {T1 <: 类参值1, T2 >: 类参值2, …}

也可以将多个类参分开表示,即:

类型名{T1, T2, …} where {T1 <: 类参值1} where {T2 >: 类参值2} …

例如:

julia> abstract type Pointy3D{T1, T2, T3} end

julia>  IntPoints  =  Pointy3D{T1,  T2,  T3}  where  {T1<:Signed}  where  {T2<:Integer} where {T3<:AbstractFloat};

julia> Pointy3D{Int32, UInt64, Float64} <: IntPoints
true

由此可见,采用协变或逆变方式对参数类型具象化时,获得的结果与前面所述大为不同。虽然提供了具体类参,但得到的仍旧是某种类似于参数类型的结构。似乎这种具象化过程仅仅是在原参数化类型的基础上打了“补丁”,进一步增加了限界规则而已。

实际上,不少语言中都存在协变与逆变机制,目的是描述一个参数类型是否沿袭了类参的继承关系:协变中,具象后的参数类型继承的父子秩序与类参是相同的;而逆变中,继承的则是相反的父子秩序。

Julia中的沿袭规则可描述为:协变时,只有S<:T满足时下式中的继承断言才会成立:

参数类型名{S} <: 参数类型名{<:T}

而协变时,只有S>:T满足时下式中的继承断言才会成立:

参数类型名{S} <: 参数类型名{>:T}

例如:
Julia协变与逆变

其中,Int32与Signed都是Integer的子类型,所以断言均成立;但Real不是Integer的子类型,所以不成立。这与前述中各具象类型之间相互独立、不存在父子关系是完全不同的,因为内部的结构发生了变化。实际上,如果查看某个具象类型的结构便会发现:

julia> dump(Pointy{Real})
Pointy{Real}

内部已经没有任何特殊结构,就是一个具体的类型。对于具象的Point1D类型也是如此:

julia> dump(Point1D{Int64})
Point1D{Int64} <: Any
  x::Int64

julia> typeof(Point1D{Int64})
DataType

可见,其已经在类型具象化的过程“蜕变”成了普通的类型;这也是具象类型间无直接继承关系而成为独立类型的根源。

对于逆变也有相似的结论,例如:

julia> Point1D{Real} <: Point1D{>:Integer}
true

julia> Point1D{Number} <: Point1D{>:Integer}
true

julia> Point1D{Int32} <: Point1D{>:Integer}
false

可见,断言的成立与类参的父子秩序是相反的。

实际上,类似于UnionAll,可以认为协变或逆变类型指代了一族类型,其中每个类型的类参值都是协变型类参的子类型,或是逆变型类参的父类型。换言之,对于协变型而言,形式Name{<:T}等效于Union{Name{S1}, Name{S2}, …},其中Si<:T总成立;对于逆变型,形式Name{>:T}等效于Union{Name{S1}, Name{S2}, …},其中Si>:T总成立。

酷客网相关文章:

赞(0)

评论 抢沙发

评论前必须登录!