2016-07-06 52 views
11

Non riesco a trovare un modo per associare il modello alla chiave di una mappa in una funzione. C'è un modo per fare questo? Quello che sto cercando di fare è eseguire codice diverso a seconda se una certa chiave esiste già in una mappa o no (e anche voluto evitare if/else e simili)Come eseguire la corrispondenza del modello sui tasti della mappa nei gruppi di funzioni in elisir

Questo è ciò che il mio codice è simile

def my_func(key, %{key => _} = map), do: ... 

che mi dà questo errore

** (CompileError) l'uso illegale di chiave variabile all'interno di carta partita chiave, mappe può abbinare solo sulla variabile esistente utilizzando^chiave

Naturalmente ho anche provato con il ^

def my_func(key, %{^key => _} = map), do: ... 

che poi dà

** (CompileError) non legato variabile^chiave

sto usando elisir 1.3.1/erlang 19.0 x64 su un computer Windows 8.1. Grazie per la lettura!

risposta

12

Proprio pattern match con la chiave è necessario:

defmodule Test do 
    def my_func(%{"a" => value}), do: {:a, value} 
    def my_func(%{"b" => value}), do: {:b, value} 
    def my_func(_), do: :error 
end 

Poi nel iEX:

iex(1)> Test.my_func(%{"a" => 1}) 
{:a, 1} 
iex(2)> Test.my_func(%{"b" => 2}) 
{:b, 2} 

Inoltre ordine delle clausole sono importanti. Per esempio, se si sta cercando di abbinare %{"b" => 2}, ma si ha la seguente mappa %{"a" => 1, "b" => 2}, la chiave "a" corrisponderà primo luogo, perché è nella prima clausola:

iex(3)> Test.my_func(%{"a" => 1, "b" => 2}) 
{:a, 1} 

Se si desidera generare qualcosa per ogni tasto è possibile abbinare Raccomando un approccio diverso. Per esempio, se si desidera mappare una funzione di quelle chiavi:

defmodule Test0 do 
    def my_op({"times_2", value}), do: {"times_2", value * 2} 
    def my_op({"times_3", value}), do: {"times_3", value * 3} 
    def my_op({key, value}), do: {key, value} 

    def my_func(m) do 
    Enum.map(m, &my_op/1) |> Enum.into(%{}) 
    end 
end 

Così si otterrebbe il seguente:

iex(1)> Test0.my_func(%{"times_2" => 2, "times_3" => 3, "whatever" => 42}) 
%{"times_2" => 4, "times_3" => 9, "whatever" => 42} 

aggiornamento in base ai commenti per questa risposta

È non è possibile associare una chiave a una variabile. Il problema è che il compilatore deve generare codice per cercare qualcosa che non sa ancora. Quando combaciano, di solito dai al compilatore alcuni suggerimenti su ciò che riceverà. Per le chiavi nelle mappe il suggerimento è la chiave stessa. In questo caso, anche indicando che il primo argomento dovrebbe essere la chiave da cercare, non è abbastanza per il compilatore. Quindi il tuo approccio dovrebbe essere quello di usare un'istruzione if:

defmodule Test2 do 
    def my_func(k, m) do 
    if Map.haskey?(k, m), do: warning(k, m), else: foo(k, m) 
    end 

    def warning(k, m) do 
    #Warning 
    m 
    end 

    # In this function you could apply the pattern matching 
    # described in the first part of this answer. 
    def foo(k, m) do 
    value = # do something 
    %{m | key => value} 
    end 
end 

Spero che questo risponda alla tua domanda.

+0

Ciao, grazie per la tua risposta.Ma probabilmente dovrei chiarire che la chiave in 'my_func (key, _)' è una variabile determinata in fase di runtime, non è nota al momento della compilazione – bottlenecked

+0

OK, ora capisco parzialmente cosa stai cercando di fare. Esattamente cosa fa la tua funzione? –

+0

Um, non pensavo fosse pertinente aggiungere il corpo della funzione, ma il codice di chiusura farà approssimativamente "se la chiave esiste già attiva un avviso, altrimenti fallo e aggiungilo alla mappa" – bottlenecked