2017-09-22 39 views
3

v06 我想写一个期望2到3个参数的签名。第一个是Integer或Integer矢量。第二个是整数矢量或整数矩阵。第三个是整数矢量或未指定。Julia无法多次发送

我第一次尝试像这样

function foo(
a::Union{Integer, Vector{Integer}}, 
b::Union{Vector{Integer}, Matrix{Integer}}, 
c::Union{Void, Vector{Integer}} = nothing) 

当我把这种喜欢这个foo(3, [0o7, 0o5])我得到一个错误,告诉我,这是无法比拟的。

ERROR: LoadError: MethodError: no method matching foo(::Int64, ::Array{UInt8,1}) 
Closest candidates are: 
    foo(::Union{Array{Integer,1}, Integer}, !Matched::Union{Array{Integer,1}, Array{Integer,2}}) at ... 
    foo(::Union{Array{Integer,1}, Integer}, !Matched::Union{Array{Integer,1}, Array{Integer,2}}, !Matched::Union{Array{Integer,1}, Void}) at ... 

现在我明白为什么Julia是无法匹配此Array{UInt8} <: Array{Integer} == false,但是这只是似乎是不聪明朱莉娅。

然后我尝试这个

foo(a::Union{Z1, Vector{Z1}}, 
    b::Union{Vector{Z2}, Matrix{Z2}}, 
    c::Union{Void, Vector{Z3}} = nothing 
    ) where {Z1 <: Integer, Z2 <: Integer, Z3 <: Integer} 

现在朱莉娅甚至没有告诉我什么不匹配!

ERROR: LoadError: MethodError: no method matching foo(::Int64, ::Array{UInt8,1}, ::Void) 
Closest candidates are: 
    foo(::Union{Array{Z1<:Integer,1}, Z1<:Integer}, ::Union{Array{Z2<:Integer,1}, Array{Z2<:Integer,2}}, ::Union{Array{Z3<:Integer,1}, Void}) where {Z1<:Integer, Z2<:Integer, Z3<:Integer} at ... 
    foo(::Union{Array{Z1<:Integer,1}, Z1<:Integer}, ::Union{Array{Z2<:Integer,1}, Array{Z2<:Integer,2}}) where {Z1<:Integer, Z2<:Integer} at ... 
+0

当你有这样非常复杂的类型签名,特别是有很多联合时,它可能是一个标志,你应该把它分成几个单独的方法定义。特别是,你可能希望至少避免使用'foo(a,b,c = Nothing)',而采用'foo(a,b,c)'和'foo(a,b)'。另外,请考虑这些类型之间是否存在关联,例如,仅当'b'是'Matrix'时'a' a'Vector'? – DNF

+0

@DNF我明白你的关注。问题是,如果我这样做,用户得到无用的茱莉亚错误消息,而不是我写的有用的。例如。 “没有方法存在,你有一个矩阵为b和c是Void”,我宁愿像这样“如果你指定b作为矩阵,你必须指定c为这些维度的向量。事实上,这个签名是检查所有内容并将所有内容都转换为正确类型后调用真实方法的废话检查签名。 – Nozdrum

+0

您正在设置自己去做大量的显式输入检查,这与多次调度的想法背道而驰。你只是为了避免让人们接触到普通的Julia错误信息而造成很大的痛苦。另外,如果我没有提供任何'c',我会惊讶地发现'c'是'Void'!建议:用正确的签名将你的功能分解成单独的方法。然后制作一个后备方法(或多个),以捕获剩下的部分:'f(a,b,c)= ...'没有类型,然后让那个人找出输入有什么问题并发出错误。 – DNF

回答

6

是,Array{UInt8} <: Array{Integer} == false。这被称为“参数不变性”。许多其他问题已经讨论过这个话题。

你正在运行之中,其他的问题虽然是当你使用一个静态函数的参数 - 也就是说,f(…) where T - 在T必须匹配的东西,因为它可用于在函数体使用。这会导致Union s中的问题,其中T在每个选项中都不可用。我相信有一个改变这种行为的开放性问题,允许匹配Union不包含T的元素,如果您尝试访问它,会将该绑定转换为未定义的变量。

现在的解决方法是使用类型变量,不是函数的静态参数。例如,

foo(a::Union{Integer, Vector{<:Integer}}, 
     b::Union{Vector{<:Integer}, Matrix{<:Integer}}, 
     c::Union{Void, Vector{<:Integer}} = nothing) = 1 
+0

IIRC,在过去当三角调度不被支持时,我们必须定义一个'typealias'来解决这个问题。 'typealias IntVector {T <:Integer} Vector {T}','foo(x :: Union {Integer,IntVector})= x'。很高兴看到这不再需要了! – Gnimuc