使用点语法访问 struct prop 时出现 Elixir Dialyzer 错误
Elixir Dialyzer error when accessing struct prop using dot syntax
更新我的项目以使用 Elixir 1.12 后,我注意到 Dialyzer 抱怨我在某些地方使用点表示法访问结构的 属性。例如,我的应用程序中有一个 graphql 解析器函数:
def update(_root, %{input: input}, %{context: %{current_user: user}}) do
case user
|> User.update_changeset(input)
|> Repo.update() do
{:ok, updated_user} ->
if user.email !== updated_user.email do
Email.email_changed(user.email, updated_user.email)
|> Mailer.deliver_later()
end
{:ok, updated_user}
err ->
err
end
end
Dialyser 突出显示了表达式 user.email !== updated_user.email
,错误如下:
The call _.'email'/() requires that _@1 is of type atom(), not {map(), map()}
知道这个错误是什么意思以及如何修复它吗?
(这一切编译和运行良好,我只是想知道为什么它似乎不满足 Dialyzer)
虽然很难判断 dialyzer 是否错误,或者您的代码是否存在导致此问题的故障,但在传递给此函数之前没有看到上下文是如何构建的,这里有一些一般性建议。
到处使用深度模式匹配来缩小问题范围。
def update(_root, %{input: input},
%{context: %{current_user: %User{email: email}}}) do
user
|> User.update_changeset(input)
|> Repo.update()
|> case do
{:ok, %User{email: ^email} = user} ->
{:ok, user}
{:ok, %User{email: updated_email} = user} ->
email
|> Email.email_changed(updated_email)
|> Mailer.deliver_later()
{:ok, user}
err ->
err
end
end
这样代码更清晰,意图更清晰,错误(如果发生)更明显并粘在它实际所属的地方。
更新我的项目以使用 Elixir 1.12 后,我注意到 Dialyzer 抱怨我在某些地方使用点表示法访问结构的 属性。例如,我的应用程序中有一个 graphql 解析器函数:
def update(_root, %{input: input}, %{context: %{current_user: user}}) do
case user
|> User.update_changeset(input)
|> Repo.update() do
{:ok, updated_user} ->
if user.email !== updated_user.email do
Email.email_changed(user.email, updated_user.email)
|> Mailer.deliver_later()
end
{:ok, updated_user}
err ->
err
end
end
Dialyser 突出显示了表达式 user.email !== updated_user.email
,错误如下:
The call _.'email'/() requires that _@1 is of type atom(), not {map(), map()}
知道这个错误是什么意思以及如何修复它吗?
(这一切编译和运行良好,我只是想知道为什么它似乎不满足 Dialyzer)
虽然很难判断 dialyzer 是否错误,或者您的代码是否存在导致此问题的故障,但在传递给此函数之前没有看到上下文是如何构建的,这里有一些一般性建议。
到处使用深度模式匹配来缩小问题范围。
def update(_root, %{input: input},
%{context: %{current_user: %User{email: email}}}) do
user
|> User.update_changeset(input)
|> Repo.update()
|> case do
{:ok, %User{email: ^email} = user} ->
{:ok, user}
{:ok, %User{email: updated_email} = user} ->
email
|> Email.email_changed(updated_email)
|> Mailer.deliver_later()
{:ok, user}
err ->
err
end
end
这样代码更清晰,意图更清晰,错误(如果发生)更明显并粘在它实际所属的地方。