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}
例如:
其中,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
总成立。
酷客网相关文章:
评论前必须登录!
注册