2016-05-16 15 views
1

Während eine Funktion zu schreiben, ich bin mit Argument Matching wie folgt:Regex und Map Argument passende

def process_thing(%{} = thing) 

Ich erwarte, dass thing eine Karte ist, und ist Enumerable. Leider stimmt diese Argumentliste auch mit Regexes überein, die als ~r/regex/ angegeben sind, und die Regex (obwohl sie für is_map(~r/thing/) true zurückgibt) ist nicht aufzählbar.

Wie kann ich diese Funktionsdefinition erstellen, sodass nur Maps - oder im Idealfall Enumerable Dinger - an diese Funktion gesendet werden?

Antwort

5

Es gibt keine Möglichkeit zu passen auf etwas, das ein Enumerable ist. Wenn Sie mit nur Karten ok sind, dann haben Sie die is_map/1 eingebaute Funktion:

def process_thing(thing) when is_map(thing) do 
    ... 
end 

Eine Alternative ist für alle Datentypen überprüft, die Sie erwarten und Unterstützung:

def process_thing(thing) when is_map(thing) or is_list(thing), do: ... 
def process_thing(%MapSet{}), do: ... 
... 

Wenn Sie müssen alle enumerables unterstützen (vielleicht wird es einfacher sein, gute Ratschläge mit mehr Informationen über Ihre Benutzung Fall zu geben), kann man immer Protocol.assert_impl!/2 verwenden:

def process_thing(thing) when is_map(thing) or is_list(thing), do: ... 
def process_thing(%{__struct__: struct}) do 
    assert_impl!(Enumerable, struct) 
end 

und den möglichen Fehler von Protocol.assert_impl!/2 behandeln. Ich bin mir nicht sicher, ob diese Implementierung kugelsicher ist und es könnte auch eine sauberere Möglichkeit geben, dies zu implementieren. :)

Eine weitere Sache: Wenn Sie auf Karten übereinstimmen sollen aber nicht auf structs passen (wie Regex), einen Weg, um es zu lösen, ist zum ersten Spiel auf die Dinge, die Sie nicht wollen so anzupassen, dass Sie erhalten sie aus dem Weg (und behandeln sie, wie Sie auch brauchen):

def process_thing(%{__struct__: _}), do: # bad things here, we don't like structs 
def process_thing(%{} = thing), do: # hey, that's a map now!