如何在函数保护条款中测试结构的值?

Ole*_*ann 11 elixir phoenix-framework

在这个小卫生功能的Phoenix/Elixir应用程序中,当用户没有输入电子邮件时,我会遇到问题.

我正在使用结构来处理数据.一个简单的卫生功能(现在)只是剥离空白并更新结构(地图).到目前为止,它的工作很好,但是当领域emailnil,我得到一个错误.

** (FunctionClauseError) no function clause matching in String.Unicode.strip/1
Run Code Online (Sandbox Code Playgroud)

所以我引入了一个guard子句来检查这种情况,然后只清理用户名.

defmodule MyApp.User do
  defstruct username: nil, email: nil, password: nil, hashed_password: nil

  # Sanitizing input without guard clause
  def sanitize_user(user)do
    %{user | username: String.strip(user.username), email: String.strip(user.email)}
  end


  # Sanitizing input with guard clause
  def sanitize_user(user) when is_nil(user.email) do
    %{user | username: String.strip(user.username)}
  end
  def sanitize_user(user) when is_binary(user.email) do
    %{user | username: String.strip(user.username), email: String.strip(user.email)}
  end
end
Run Code Online (Sandbox Code Playgroud)

现在我在编译时遇到错误:

** (CompileError) web/models/user.ex:54: cannot invoke remote function Access.get/2 inside guard
Run Code Online (Sandbox Code Playgroud)

我想是因为这个字段的值在编译时不可用.或类似的东西.

怎么解决这个?如何测试保护条款中结构的值?

Gaz*_*ler 23

您对编译时无法获得的值的假设是正确的.但是,您可以模式匹配地图中的值并在警卫中使用它们.

你可以编写你的函数:

  def sanitize_user(%MyApp.User{email: nil} = user) do
    %{user | username: String.strip(user.username)}
  end
  def sanitize_user(%MyApp.User{email: email} = user) when is_binary(email) do
    %{user | username: String.strip(user.username), email: String.strip(user.email)}
  end
Run Code Online (Sandbox Code Playgroud)

如果要允许传递其他结构(在这种情况下不太可能),也可以在没有User结构的地图上匹配:

  def sanitize_user(%{email: nil} = user)
Run Code Online (Sandbox Code Playgroud)