在v0.6的Julia手册中,我找到以下内容:
abstract type Pointy{T} end
struct Point{T} <: Pointy{T}
x::T
y::T
end
这很好用,我认为还应该如下:
abstract type Foo{V, F} end
struct Bar{V, F} <: Foo{V, F}
x::V{F}
end
Bar
的定义给出了以下错误
ERROR: TypeError: Type{...} expression: expected UnionAll, got TypeVar
有什么问题,我怎样才能实现我真正想要的,即指定V<:AbstractVector
和F<:AbstractFloat
?
答案 0 :(得分:3)
试试这个:
julia> abstract type Foo{T} end
julia> struct Bar{T<:AbstractFloat,V<:AbstractVector{T}} <: Foo{T}
x::V
end
julia> Bar{T}(v::AbstractVector{T}) = Bar{T,typeof(v)}(v) # constructor
Bar
julia> Bar(rand(3))
Bar{Float64,Array{Float64,1}}([0.387467, 0.535419, 0.240748])
julia> Bar(rand(Int, 3))
ERROR: TypeError: Bar: in T, expected T<:AbstractFloat, got Type{Int64}
Stacktrace:
[1] Bar(::Array{Int64,1}) at ./REPL[4]:1
答案 1 :(得分:2)
另一种选择(让它与@ tholy的答案同时工作并使用相同的路线来获得V&#34;包括&#34;参数F)。为了让它工作得很好,应该添加一个外部构造函数,比如@ tholy的答案(可能这有点多余,但它使用where
语法)
struct Bar{V, F} <: Foo{V,F}
x::V
Bar{V,F}(x::V) where {F, V<:AbstractVector{F}} = new(x)
end
这就是这样的:
julia> Bar{Vector{Int},Int}([1,2,3])
Bar{Array{Int64,1},Int64}([1, 2, 3])
julia> Bar{Vector{Int},Float64}([1,2,3])
ERROR: MethodError: Cannot `convert` an object of type Array{Int64,1} to an object of type Bar{Array{Int64,1},Float64}
This may have arisen from a call to the constructor Bar{Array{Int64,1},Float64}(...),
since type constructors fall back to convert methods.
答案 2 :(得分:1)
根据@tholy和@DanGetz的答案,我搞砸了一下,想出了一个我喜欢的答案:
abstract type Foo{V} end
struct Bar{V <: AbstractVector{<:AbstractFloat}} <: Foo{V}
x::V
end
julia> Bar(rand(5))
Bar{Array{Float64,1}}([0.722314, 0.159418, 0.13561, 0.288794, 0.347009])
julia> Bar(2.0:5.0)
Bar{StepRangeLen{Float64,Base.TwicePrecision{Float64},Base.TwicePrecision{Float64}}}(2.0:1.0:5.0)
julia> Bar(2:5)
ERROR: MethodError: Cannot `convert` an object of type UnitRange{Int64} to an object of type Bar
我喜欢这个,因为它似乎更简单,默认构造函数直接工作,而且我没有得到浮点类型变量“加倍”,即Bar{Array{Float64,1}}
而不是Bar{Float64,Array{Float64,1}}
。
不确定此版本是否有任何缺点。另外,我仍然不明白为什么我的一些努力会起作用,而有些则因语法或其他错误而失败。