Wie initialisieren Sie in Elixir eine Struktur mit einer Map-Variablen?


72

Ich weiß, dass es möglich ist, eine Struktur über zu erstellen %User{ email: 'blah@blah.com' }. Aber wenn ich eine Variable hätte, params = %{email: 'blah@blah.com'}gibt es eine Möglichkeit, diese Struktur mit dieser Variablen zu erstellen, z %User{ params }.

Dies gibt einen Fehler aus und fragt sich nur, ob Sie ihn explodieren können oder auf andere Weise?

Antworten:


112

Sie sollten die struct/2Funktion verwenden. Aus den Dokumenten:

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"}

4
Wenn Sie Schlüssel erzwungen haben und sicherstellen möchten, dass sie in der Karte vorhanden sind, verwenden Sie struct!/2stattdessen.
RusinaRange

4
Ich bin verwirrt. Diese Antwort zeigt die Initialisierung einer Struktur aus einer Schlüsselwortliste. Aber die Frage fragt nach Struktur aus einer Karte.
Ahmad Ferdous

2
Ich habs! struct/2funktioniert auch für eine Karte. Also opts = %{name: "meg"}funktioniert.
Ahmad Ferdous

27

Die vorherigen Antworten sind beide gut, mit einer Einschränkung: Die Schlüssel in der Struktur sind Atome, die Schlüssel in Ihrem Hash können Zeichenfolgen sein. Bei Verwendung der struct () -Methode werden nur die übereinstimmenden Schlüssel kopiert, und Zeichenfolgen stimmen nicht mit den Atomen überein. Beispiel:

defmodule User do
  defstruct name: "john"
end

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

Die Verwendung von Merge ist ebenfalls seltsam, da dadurch die Struktur der Map "rückgängig gemacht" wird:

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

Fand dies in der elixir-lang-talk Google Group von Jose selbst:

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

Das ist so ziemlich der richtige Weg, außer dass Sie alles in einem Durchgang erledigen können:

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

1
Joses Antwort (und Ihre durch Abzug) sollte die akzeptierte sein, weil sie von Jose stammt (Scherz). Die Verwendung von Merge hat mir Probleme bereitet, und ja, Sie verlieren die Struktur vollständig.
SixFingers

Vielen Dank dafür, ich brauchte eine ziemlich allgemeine Methode, um Strukturen aus allen Arten von Karten zu initialisieren, und dies war die Grundlage meines Hacks, um dies zu tun. Github.com/chrisjowen/ExMapper
Owen

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.