2016-08-20 8 views

Antwort

4

Verwenden String.to_existing_atom/1 und Map.get/2 (als structs tatsächlich Karten sind):

iex(1)> defmodule MyStruct do 
...(1)> defstruct [:key1, :key2] 
...(1)> end 
iex(2)> var1 = "key1" 
"key1" 
iex(3)> struct1 = %MyStruct{key1: "fdsfd", key2: 33} 
%MyStruct{key1: "fdsfd", key2: 33} 
iex(4)> val1 = Map.get(struct1, String.to_existing_atom(var1)) 
"fdsfd" 

Die [:key] Syntax wird nicht mit structs arbeiten Standardmäßig wird das Protokoll Access verwendet, das vom Benutzer für jede Struktur implementiert werden muss.

String.to_existing_atom/1 wird einen Fehler ausgeben, wenn das Atom noch nicht existiert, aber sicherer ist als die Konvertierung beliebiger Eingaben in Atom und es wird definitiv existieren, wenn Sie eine Struktur mit diesem Schlüssel bereits definiert haben. Weitere Details finden Sie unter this question.

+0

ist es notwendig, var1 an ein Atom zu konvertieren? – Johshi

+0

Sie könnten iterieren Alle Felder der Struktur, konvertieren Sie die Schlüssel in Zeichenfolge, und vergleichen Sie diese, aber es wäre viel langsamer. So etwas wie: 'struct1 |> Map.from_struct |> Enum.find (fn {Schlüssel, _} -> Atom.to_string (key) == var1 end)'. – Dogbert

+0

aber ist kein Atom ein Schlüssel einer Struct Synonim zu einer Zeichenkette? – Johshi

1

Neben Map.get/2 können Sie Muster vergleichen, um den Wert zu erhalten, oder implementieren Sie das Access-Verhalten auf Ihrer Struktur, so können Sie struct1[var1] verwenden, wie Sie versuchten.

(Schalten Sie das var1 = "key1" in einem Atom mit String.to_existing_atom/1 wie vorgeschlagen.)

Bei einem struct1 = %MyStruct{key1: "fdsfd", key2: 33}

Pattern Matching:

iex> %{^var1 => value} = struct1 
iex> value 
"fdsfd" 

Zugriffsverhalten:

defmodule MyStruct do 
    defstruct key1: nil, key2: nil 

    def fetch(my_struct, key) do 
    {:ok, Map.get(my_struct, key)} 
    end 
end 

iex> my_struct[var1] 
"fdsfd" 

Beachten Sie, dass Ich habe es nicht umgesetzt das vollständige Zugriffsverhalten. Siehe http://elixir-lang.org/docs/stable/elixir/Access.html#callbacks

+0

Um noch einmal das Argument string vs atom zu kommentieren: Sie könnten 'fetch (my_struct, key) implementieren wenn is_binary (key), do: fetch (my_struct, String.to_existing_atom (key))', wenn Sie auf Strukturfelder zugreifen wollten mit Zeichenfolgen, mit dem Access-Verhalten. Ich würde es aber trotzdem empfehlen. Es verdunkelt Ihre tatsächlichen Daten und könnte dazu führen, dass Sie denken, Sie haben String-Schlüssel in einem anderen Kontext. –

0

Wenn Sie mit Elixir 1.3 oder höher, können Sie die Access.key! mit get_in auf jede Struktur verwenden:

var1 = "key1" 
struct1 = %MyStruct{key1: "fdsfd", key2: 33} 

val1 = get_in struct1, [Access.key!(String.to_existing_atom())] 

Vor Elixir 1.3 ist es nicht möglich war get_in/3 zu verwenden (wo die Lookup-Pfad ist variabel. Vor Elixir 1.3, nur get_in/2 wie val1 = get_in struct1.var1 nutzen könnten. Access.key! den schönen Vorteil hat, wie es funktionieren wird KeyError erhöhen.

Verwandte Themen