2015-10-24 11 views
18

Ho notato una funzione con un trailing esclamazione marchio/Bang (!), Mentre passa attraverso il tutorial Phoenix (nella sezione Incoming Events)Che cosa sono le funzioni di Elixir Bang?

def handle_in("new_msg", %{"body" => body}, socket) do 
    broadcast! socket, "new_msg", %{body: body} 
    {:noreply, socket} 
end 

Cosa significa il punto esclamativo finale? Fa qualcosa? Ho cercato in giro e ho cercato di guardare ma non sono sicuro di usare i termini giusti. Finora sembra che la funzione solo come convenzione solleverà un errore se fallisce, ma lo fa sempre sempre.

L'menziona solo che vedo di apparire in "Programmazione Elixir" di Dave Thomas:

Identifiers in Elixir are combinations of upper and lower case ASCII 
characters, digits, and underscores. Function names may end with a 
question mark or an exclamation point. 

E anche in the documentation si parla:

Notice that when the file does not exist, the version with ! raises an 
error. The version without ! is preferred when you want to handle 
different outcomes using pattern matching... 

Nessuno di questi spiega se questa è una convenzione che altri elisiristi o alchimisti o qualunque uso. Per favore aiuto.

risposta

10

questo:

Si noti che quando il file non esiste, la versione con! solleva un errore . La versione senza! è preferito quando si vuole gestire diversi risultati utilizzando pattern matching ...

sarà più chiaro se si guarda il codice sorgente. Il simbolo ! in un nome di funzione è solo un accordo sintattico. Se vedi una funzione che contiene il simbolo ! nel suo nome, significa che probabilmente esiste una funzione con lo stesso nome, ma senza il simbolo !. Entrambe queste funzioni faranno la stessa cosa, ma gestiranno gli errori in un modo diverso.

La funzione senza ! restituirà un errore. Dovrai conoscere un tipo di errore e gestirlo in base al tuo tipo. Guarda sulla funzione broadcast/3 (variant senza !):

def broadcast(server, topic, message) when is_atom(server), 
    do: call(server, :broadcast, [:none, topic, message]) 

rende solo chiamata al server dato e tornerà il suo risultato. La funzione broadcast!/3 farà lo stesso, ma: si chiamerà broadcast funzione senza !, controllerà il suo risultato ed aumentare il BroadcastErrorexception:

def broadcast!(server, topic, message) do 
    case broadcast(server, topic, message) do 
     :ok -> :ok 
     {:error, reason} -> raise BroadcastError, message: reason 
    end 
    end 
+0

Grazie per il tempo dedicato a fornire un buon esempio dalla fonte di Phoenix. Risponde perfettamente alla mia domanda. Ero bloccato tra la tua risposta e quella che ho scelto perché entrambi spiegavano bene la mia domanda. Ho scelto di non selezionare questo solo perché si concentra sull'uso di Phoenix del '!' E, sfortunatamente non espresso nella mia domanda, sono interessato alle convenzioni di Elisir un po 'più di Phoenix. – Marc

+1

Mangerò le mie stesse parole - e accetterò la tua risposta perché sottolinea un dettaglio importante come menzionato da @MoxleyStratton - "La convenzione bang si applica alle situazioni in cui ci sono due versioni di una funzione - una che solleva un'eccezione (la versione bang), e uno che non lo fa. " – Marc

2

Che, fondamentalmente capito bene Marc - si tratta di una convenzione per dire sollevano UN ERRORE se le cose vanno male.

Non v'è documentazione, nel suo genere, in questa page che parla di accesso File (scorrere fino alla frase finale botto)

+0

Il mio problema principale è che la documentazione viene fatta di passaggio e noi, come comunità di elisir, ci aspettiamo di cogliere le sottigliezze. Sono contento di essere riuscito a carpire qualcosa e di aver fornito la 'documentazione della comunità 'del suo uso accettato :) TY – Marc

+0

Trovo che questa risposta sia fuorviante. Leggendolo, uno sviluppatore potrebbe concludere che quando si crea una funzione che genera un errore, dovrebbe essere chiamata con un botto (!). Questo non è l'intento della convenzione del botto. @ 0xAX ha capito bene che vedendo una funzione bang "significa che probabilmente c'è una funzione con lo stesso nome, ma senza! Simbolo". La convenzione bang si applica alle situazioni in cui esistono due versioni di una funzione, una che solleva un'eccezione (la versione bang) e una che non lo fa. –

+0

@MoxleyStratton ripensa a questa domanda (e accetta la risposta) Sono d'accordo con te (e non sono d'accordo con la mia precedente decisione). – Marc

11

Il suo solo una convenzione di denominazione. Controlla questa risposta - What's the meaning of "!", "?", "_", and "." syntax in elixir

! - Solleverà un'eccezione se la funzione rileva un errore.

Un buon esempio è Enum.fetch! (Ha anche lo stesso Enum.fetch che non genera eccezioni).Trova l'elemento all'indice indicato (a base zero). Solleva OutOfBoundsError se la posizione data è al di fuori dell'intervallo della collezione.

+0

Grazie per aver trovato il riferimento che stavo cercando qui su SO. Speravo che ciò che avresti linkato avrebbe qualche riferimento alla documentazione ufficiale, ma immagino che dovrà fare. Vengo da un mondo pitone pieno di articoli PEP e simili in cui più di un paio di paragrafi sono dedicati al "perché", quindi sono un po 'deluso dal fatto che lo stesso processo di pensiero pubblico non è disponibile, ma questo sarà devo fare. – Marc

+0

felice di aiutare, e anche l'elisir è nuovo e migliora ogni giorno, inclusa la documentazione. Quindi penso che i documenti, presto raggiungeranno il livello che si aspettano da loro. – coderVishal

+1

Sono ancora molto grato per la fonte che hai indicato, tuttavia ora (guardando indietro) ho spostato la risposta corretta a @ 0xAX a causa dell'enfasi posta sulle versioni doppie di una funzione. Spero tu sia d'accordo con la decisione. – Marc

Problemi correlati