2017-09-22 99 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