"Dialyzer is usually never wrong",但我无法弄清楚我的@spec 是如何不正确的
"Dialyzer is usually never wrong", but I can't figure out how my @spec is incorrect
我有一些代码使透析器失败,我不明白为什么。无论我在函数顶部的 @spec
中放入什么,对该函数的调用 return 都是一个令人费解的透析器错误。这是功能的简化。据我所知,我已经正确指定了函数。
@spec balances(uuid :: String.t(), retries :: non_neg_integer) ::
{:ok, list()}
| {:internal_server_error, String.t(), String.t()}
| {:internal_server_error, map | list, String.t()}
def balances(uuid, retries \ 0) do
url = "/url/for/balances" |> process_url
case HTTPoison.get(
url,
[, {"Content-Type", "application/json"}],
[]
) do
{:ok, %HTTPoison.Response{status_code: 200, body: body}} ->
response = Poison.decode!(body, as: %{"message" => [%Currency{}]})
cond response["message"] do
length(bal) > 0 ->
{:ok, bal}
retries >= 1 ->
{:ok, []}
true ->
init(uuid)
balances(uuid, retries + 1)
end
{:error, %HTTPoison.Error{reason: reason}} ->
Notifier.notify(url, reason, Helpers.line_info(__ENV__))
{:internal_server_error, reason, url}
{_, %HTTPoison.Response{body: body} = res} ->
response = Poison.decode!(body)
Notifier.notify(url, response, Helpers.line_info(__ENV__))
{:internal_server_error, response, url}
end
end
我的问题是,如果我希望获得除 {:ok, balances}
:
以外的任何内容,那么每次跨代码库对此函数的调用都会失败
user_balances =
case balances(uuid) do
{:ok, user_balances} -> user_balances
_ -> [] # Dialyzer error here
end
Dialyzer 警告 The variable _ can never match since previous clauses completely covered the type {'ok',[map()]}
。我读到这意味着任何对 balances 的调用总是 return {:ok, balances}
,但这不可能是真的,因为 HTTPoison.get
的 case 语句是函数中最后计算的东西,并且它似乎只有三种可能的结果:
{:ok, list}
{:internal_server_error, String.t(), String.t()}
{:internal_server_error, map | list, String.t()}
.
我知道我可能遗漏了一些非常明显的东西,但我不知道是什么。任何帮助将不胜感激。谢谢!
感谢@legoscia 的评论,我调查了对 Notifier.notify
的调用,果然在该函数中也有一个透析器警告(我已经向一个开源项目提交了 PR 以修复规范导致通知功能使透析器失败)。如果我修改 notify 函数使得没有警告发生,那么对 balances
的调用肯定不会再产生透析器警告。
tl;dr 如果 dialyzer 向您发出有关似乎未正确指定的函数的警告,请开始检查函数中的函数调用以查找下游 dialyzer 错误。
我有一些代码使透析器失败,我不明白为什么。无论我在函数顶部的 @spec
中放入什么,对该函数的调用 return 都是一个令人费解的透析器错误。这是功能的简化。据我所知,我已经正确指定了函数。
@spec balances(uuid :: String.t(), retries :: non_neg_integer) ::
{:ok, list()}
| {:internal_server_error, String.t(), String.t()}
| {:internal_server_error, map | list, String.t()}
def balances(uuid, retries \ 0) do
url = "/url/for/balances" |> process_url
case HTTPoison.get(
url,
[, {"Content-Type", "application/json"}],
[]
) do
{:ok, %HTTPoison.Response{status_code: 200, body: body}} ->
response = Poison.decode!(body, as: %{"message" => [%Currency{}]})
cond response["message"] do
length(bal) > 0 ->
{:ok, bal}
retries >= 1 ->
{:ok, []}
true ->
init(uuid)
balances(uuid, retries + 1)
end
{:error, %HTTPoison.Error{reason: reason}} ->
Notifier.notify(url, reason, Helpers.line_info(__ENV__))
{:internal_server_error, reason, url}
{_, %HTTPoison.Response{body: body} = res} ->
response = Poison.decode!(body)
Notifier.notify(url, response, Helpers.line_info(__ENV__))
{:internal_server_error, response, url}
end
end
我的问题是,如果我希望获得除 {:ok, balances}
:
user_balances =
case balances(uuid) do
{:ok, user_balances} -> user_balances
_ -> [] # Dialyzer error here
end
Dialyzer 警告 The variable _ can never match since previous clauses completely covered the type {'ok',[map()]}
。我读到这意味着任何对 balances 的调用总是 return {:ok, balances}
,但这不可能是真的,因为 HTTPoison.get
的 case 语句是函数中最后计算的东西,并且它似乎只有三种可能的结果:
{:ok, list}
{:internal_server_error, String.t(), String.t()}
{:internal_server_error, map | list, String.t()}
.
我知道我可能遗漏了一些非常明显的东西,但我不知道是什么。任何帮助将不胜感激。谢谢!
感谢@legoscia 的评论,我调查了对 Notifier.notify
的调用,果然在该函数中也有一个透析器警告(我已经向一个开源项目提交了 PR 以修复规范导致通知功能使透析器失败)。如果我修改 notify 函数使得没有警告发生,那么对 balances
的调用肯定不会再产生透析器警告。
tl;dr 如果 dialyzer 向您发出有关似乎未正确指定的函数的警告,请开始检查函数中的函数调用以查找下游 dialyzer 错误。