可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
In the Julia manual for v0.6 I find the following:
abstract type Pointy{T} end struct Point{T} <: Pointy{T} x::T y::T end
This works fine, and I thought the following should as well:
abstract type Foo{V, F} end struct Bar{V, F} <: Foo{V, F} x::V{F} end
The definition of Bar
gives, however, the following error
ERROR: TypeError: Type{...} expression: expected UnionAll, got TypeVar
What is wrong, and how can I achieve what I really want, namely to specify that V<:AbstractVector
and F<:AbstractFloat
?
回答1:
Try this:
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
回答2:
Another option (got it to work concurrently with @tholy's answer and uses the same route of having V "include" the parameter F). To get it to work nicely, an external constructor should be added, like @tholy's answer (maybe this was a bit redundant, but it uses the where
syntax)
struct Bar{V, F} <: Foo{V,F} x::V Bar{V,F}(x::V) where {F, V<:AbstractVector{F}} = new(x) end
and this works like so:
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.
回答3:
Based on the answers of @tholy and @DanGetz I messed about a bit and came up with an answer I liked:
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
I like this because it seems simpler, the default constructor works directly, and I don't get "doubling" of the floating point typevar, that is, Bar{Array{Float64,1}}
instead of Bar{Float64,Array{Float64,1}}
.
Not sure if there are any drawbacks to this version, though. Also, I still don't understand why some of my efforts work and some fail with syntax or other errors.