在這種情況下,透析器對我來說表現得很奇怪,我還沒有找到任何可以更好地理解它的東西。爲什麼不透析器檢測到這種不良類型?
這是不是一個錯誤:
defmodule Blog.UserResolver do
@type one_user :: ({:error, String.t})
@spec find(%{id: String.t}, any()) :: one_user
def find(%{id: id}, _info) do
age = :rand.uniform(99)
if (age < 100) do
# This doesn't trigger a type error, even though it's wrong
{:ok, %{email: "[email protected]", name: "Deedub"}}
else
{:error, "Age isn't in the right range"}
end
end
end
注意可能的返回分支絕對的一個不匹配的類型簽名。
然而,這確實有一個錯誤:
defmodule Blog.UserResolver do
@type one_user :: ({:error, String.t})
@spec find(%{id: String.t}, any()) :: one_user
# Throws an error since no return path matches the type spec
def find(%{id: id}, _info) do
age = :rand.uniform(99)
if (age < 100) do
{:ok, %{email: "[email protected]", name: "Deedub"}}
else
10
end
end
end
在這種情況下,沒有可能的分支的的類型指定匹配,並且透析說有此錯誤消息:
web/blog/user_resolver.ex:4: Invalid type specification for function 'Elixir.Blog.UserResolver':find/2. The success typing is (#{'id':=_, _=>_},_) -> 10 | {'ok',#{'email':=<<_:64>>, 'name':=<<_:48>>}}
我不明白的部分是透析器明確承認分支可能會返回兩種不同類型((#{'id':=_, _=>_},_) -> 10 | {'ok',#{'email':=<<_:64>>, 'name':=<<_:48>>}
),所以它不是推論的問題。那麼,爲什麼它不認識到其中一個分支不符合類型規範(它似乎很高興,如果只是一個的分支符合,這不是我想要的)
我認爲這裏的「成功打字」部分解釋了這一點:http://learnyousomeerlang.com/dialyzer。 「請記住,Dialyzer是樂觀的,它對代碼具有比喻性的信念,並且因爲在某個時候調用convert/1函數成功的可能性,Dialyzer將保持沉默,在這種情況下沒有報告類型錯誤。 – Dogbert
但這看起來不直觀 - 在錯誤消息中*清楚*可以檢測到每種可能的返回類型。也許這只是一個我可以設置的標誌,說:「告訴我,如果其中一個分支不符合類型規格」? 如果可能,我正在尋找更嚴格的類型檢查程序,並且如果有必要,很樂意通過額外的挑戰來解決問題。 – sgrove
你可以這樣看:如果型號規格可以成功,Dialyzer不會報告任何錯誤,因爲不完整的定義是有意的。在你的第一個例子中,你可以想象你的函數的正常(和記錄)行爲是返回'{:error,String.t}'(怪異不是它),而其他情況不應該發生 – Pascal