【发布时间】:2017-09-22 14:17:01
【问题描述】:
v06 我想写一个需要 2 到 3 个参数的签名。第一个是整数或整数向量。第二个是整数向量或整数矩阵。第三个是整数向量或未指定。
我第一次是这样尝试的
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,但这似乎是 julia 的不聪明。
然后我尝试了这个
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 ...
【问题讨论】:
-
当你有像这样的非常复杂的类型签名时,尤其是有很多联合时,这可能表明你应该把它分成几个单独的方法定义。特别是,您可能希望至少避免使用
foo(a, b, c=nothing),而支持foo(a, b, c)和foo(a, b)。另外,还要考虑类型之间是否存在联系,例如只有当b是Matrix时,是a还是Vector? -
@DNF 我理解您的担忧。问题是,如果我这样做,用户会收到无用的 julia 错误消息,而不是我编写的有用的错误消息。例如。 “没有方法存在 b 且 c 为 Void 的矩阵”,我宁愿这样“如果将 b 指定为矩阵,则必须将 c 指定为具有这些维度的向量”。事实上,这个签名是在检查所有内容并将所有内容转换为正确类型后调用真实方法的废话检查签名。
-
您正在设置自己进行大量显式输入检查,这与多分派的想法背道而驰。为了避免让人们接触到普通的 Julia 错误消息,你给自己造成了很大的痛苦。另外,如果我根本没有提供任何
c,我会惊讶地告诉c是Void!建议:将您的函数拆分为具有正确签名的单独方法。然后制作一个(或多个)后备方法来捕获其余部分:f(a, b, c) = ...不带类型,并让其找出输入的问题并发出错误。 -
不确定你想要什么,但类似:
foo(a::Integer, b::Vector{<:Integer}) = ... endfoo(a::Vector{<:Integer}, b::Matrix{<:Integer}, c::Vector{<:Integer}) = ... endfoo(a::Integer, b...) = error("If a is an Integer, b must be a Vector of Integers.") endfoo(a::Vector{<:Integer}, b...) = error("If a is an Vector of Integers, b must be a Matrix of Integers and c must be a Vector of Integers...") end(为了便于阅读,添加了结尾,实际上使用它们并不正确。)我认为这会实际上更容易编写好的错误消息。 -
对于我目前的问题,我认为这样做没有好处。我不相信这会使我的代码更具可读性。
标签: julia