MethodError when dispatching on a parametric vector of vectors

江枫思渺然 提交于 2021-01-27 06:39:25

问题


I've written a function that dispatches on a vector of vectors of Integers. 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

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!