web-dev-qa-db-fra.com

Dans Elixir, comment initialisez-vous une structure avec une variable de carte

Je sais qu'il est possible de créer une structure via %User{ email: '[email protected]' }. Mais si j'avais une variable params = %{email: '[email protected]'} existe-t-il un moyen de créer cette structure en utilisant cette variable, par exemple, %User{ params }.

Cela donne une erreur, vous vous demandez simplement si vous pouvez l'exploser ou d'une autre manière?

67
bullfrog

Vous devez utiliser le struct/2 fonction. De la documentation:

defmodule User do
  defstruct name: "john"
end

struct(User)
#=> %User{name: "john"}

opts = [name: "meg"]
user = struct(User, opts)
#=> %User{name: "meg"}

struct(user, unknown: "value")
#=> %User{name: "meg"}
103
José Valim

Les réponses précédentes sont toutes les deux bonnes, avec une mise en garde: les clés de la structure sont des atomes, les clés de votre hachage peuvent être des chaînes. L'utilisation de la méthode struct () copiera uniquement les clés qui correspondent et les chaînes ne correspondront pas aux atomes. Exemple:

defmodule User do
  defstruct name: "john"
end

opts = %{"name" => "meg"}
user = struct(User, opts)
#=> %User{name: "john"}

L'utilisation de la fusion est également étrange, car elle "annulera" la nature structurelle de la carte:

user = Map.merge(%User{}, opts)
#=> %{:__struct__ => User, :name => "john", "name" => "meg"}

J'ai trouvé cela sur le groupe Google elixir-lang-talk, de Jose lui-même:

https://groups.google.com/d/msg/elixir-lang-talk/6geXOLUeIpI/L9einu4EEAAJ

C'est à peu près la voie à suivre, sauf que vous pouvez tout faire en un seul passage:

def to_struct(kind, attrs) do
  struct = struct(kind)
  Enum.reduce Map.to_list(struct), struct, fn {k, _}, acc ->
    case Map.fetch(attrs, Atom.to_string(k)) do
      {:ok, v} -> %{acc | k => v}
      :error -> acc
    end
  end
end
25
dotdotdotPaul

Une autre façon de le faire en utilisant Map.merge/2 :

fusionner (map1, map2)

Exemple:

params
#=> %{email: "[email protected]"}

%User{} |> Map.merge(params)
#=> %User{ email: '[email protected]' }
16
Sheharyar