问题
I've written a function that dispatches on a vector of vectors of Integer
s. However, I get a MethodError when I try to use it:
julia> foo(x::Vector{Vector{<:Integer}}) = last(last(x));
julia> x = [[1], [2, 3], [4, 5, 6]]
3-element Array{Array{Int64,1},1}:
[1]
[2, 3]
[4, 5, 6]
julia> foo(x)
ERROR: MethodError: no method matching foo(::Array{Array{Int64,1},1})
Closest candidates are:
foo(::Array{Array{#s17,1} where #s17<:Integer,1}) at REPL[1]:1
Why doesn't this work?
回答1:
The notation here is a little subtle. The parametric type that you've declared for the x
argument, Vector{Vector{<:Integer}}
is a shorthand notation for Vector{Vector{T} where T<:Integer}
:
julia> Vector{Vector{<:Integer}}
Array{Array{#s17,1} where #s17<:Integer,1}
julia> Vector{Vector{T} where T<:Integer}
Array{Array{#s17,1} where #s17<:Integer,1}
Most importantly, note that Vector{Vector{T} where T<:Integer}
is not equivalent to Vector{Vector{T}} where T<:Integer
. In the former type, the concrete integer type of the inner vector elements can be different for each inner vector. In the latter type, all the inner vectors have elements of the same concrete integer type.
Furthermore, it is tricky to instantiate a literal array of type Vector{Vector{T} where T<:Integer}
, because the literal array constructor promotes the types of its arguments:
julia> typeof([Int8(1), Int16(2)])
Array{Int16,1}
julia> typeof([Int8[1], Int16[2, 3]])
Array{Array{Int16,1},1}
However, it can be done as follows,
julia> foo(x::Vector{Vector{<:Integer}}) = last(last(x));
julia> y = Vector{<:Integer}[Int8[1], Int16[2, 3], Int32[4, 5, 6]]
3-element Array{Array{#s17,1} where #s17<:Integer,1}:
Int8[1]
Int16[2, 3]
Int32[4, 5, 6]
julia> foo(y)
6
where we have made extensive use of typed array initializers.
Alternatively, if you're fine with requiring the elements of each inner array to have the same concrete integer type, you could define your function as follows:
julia> bar(x::Vector{Vector{T}}) where T<:Integer = last(last(x));
julia> x = [[1], [2, 3], [4, 5, 6]]
3-element Array{Array{Int64,1},1}:
[1]
[2, 3]
[4, 5, 6]
julia> bar(x)
6
Note that this method won't accept a vector of vectors where the concrete integer types are different:
julia> bar(y)
ERROR: MethodError: no method matching bar(::Array{Array{#s17,1} where #s17<:Integer,1})
Closest candidates are:
bar(::Array{Array{T,1},1}) where T<:Integer at REPL[35]:1
For a related discussion, see the section of the Julia manual on UnionAll types.
来源:https://stackoverflow.com/questions/59758161/methoderror-when-dispatching-on-a-parametric-vector-of-vectors