Restituire più di un valore
Elenca i tipi dei risultati tra parentesi. Restituisci i valori separati da virgole, e ricevili allo stesso modo.
Le funzioni predefinite min e max esistono da Go 1.21. Chi chiama deve ricevere ogni risultato: x := minMax(nums) non compila e dà assignment mismatch: 1 variable but minMax returns 2 values.
La convenzione (valore, error)
Il motivo più comune per restituire due valori è segnalare un fallimento. Per convenzione l'errore viene per ultimo, e quando non è nil gli altri risultati vanno considerati privi di significato.
Output:
port: 8080
error: port "http": strconv.Atoi: parsing "http": invalid syntax
error: port out of range
In caso di fallimento restituisci lo zero value per ogni altro risultato (0, "", nil). Lo schema completo, compresi wrapping e controlli, è nella pagina sulla gestione degli errori.
L'idioma comma-ok
Diverse operazioni predefinite restituiscono un secondo valore bool facoltativo che dice se il primo valore è reale. Per convenzione la variabile si chiama ok.
Queste tre forme (ricerca in una map, type assertion, ricezione da un channel) sono speciali: restituiscono uno o due valori a seconda di quante variabili assegni. Le tue funzioni non possono farlo. Una funzione dichiarata con due risultati ne restituisce sempre due.
L'identificatore vuoto
_ riceve un valore e lo butta via. Usalo per i risultati che non ti servono:
_, err := fmt.Sscan(input, &n)
key, _ := parseLine(line)
Ignorare un errore con _ compila, quindi fallo solo quando sai che la chiamata non può fallire o che il fallimento non conta. strings.Builder.WriteString restituisce sempre un errore nil, per esempio; la chiusura di un file dopo averci scritto no.
Risultati con nome
I parametri di risultato possono avere un nome. Vengono dichiarati all'inizio della funzione, inizializzati ai loro zero value, e un return senza valori restituisce quello che contengono.
I nomi compaiono nell'output di go doc, il che aiuta quando due risultati hanno lo stesso tipo: (quotient, remainder int) dice più di (int, int).
Un return nudo in una funzione lunga è difficile da leggere, perché chi legge deve tornare indietro per vedere cosa contengono i risultati. Il consiglio abituale: dai un nome ai risultati quando i nomi documentano qualcosa, e scrivi comunque return quotient, remainder in modo esplicito, a meno che la funzione non sia lunga poche righe.
Risultati con nome e defer
Una funzione in defer viene eseguita dopo che l'istruzione return ha impostato i risultati e prima che chi chiama li riceva. Con i risultati con nome, la funzione in defer può leggerli e cambiarli. È così che aggiungi contesto a qualsiasi errore restituito da una funzione, o trasformi un panic in un errore.
Stampa load : empty name e poi <nil>. return errors.New(...) prima assegna a err, poi la funzione in defer lo avvolge. Approfondisci in defer.
Shadowing di un risultato con nome
I risultati con nome vivono nello scope più esterno della funzione. Un := dentro un blocco annidato crea una nuova variabile con lo stesso nome, e un return nudo restituisce allora quella esterna.
func find() (n int, err error) {
if true {
n, err := compute() // new n and err, shadowing the results
_ = n
_ = err
}
return // returns 0, nil
}
Il compilatore intercetta il caso peggiore: un return nudo dentro il blocco in cui un risultato è oscurato fallisce con result parameter err not in scope at return. Non intercetta la versione qui sopra, dove il return sta fuori dal blocco. Usa = invece di := quando intendi le variabili di risultato.
Errori comuni
- Usare il valore quando err non è nil. Controlla prima
err. Una funzione è libera di restituire valori senza senso insieme a un errore. - Restituire un puntatore nil tipizzato come errore.
var e *MyErr; return erestituisce unerrornon nil. In caso di successo restituisci unnilletterale. - Troppi risultati. Tre o più risultati con significati diversi sono scomodi da usare. Restituisci invece una struct.
Domande frequenti
Come si restituiscono più valori da una funzione in Go?
Elenca i tipi dei risultati tra parentesi e restituisci i valori separati da virgole: func minMax(xs []int) (int, int) { ...; return lo, hi }. Chi chiama li assegna tutti insieme: lo, hi := minMax(nums).
Come ignoro uno dei valori di ritorno in Go?
Assegnalo all'identificatore vuoto _: _, err := strconv.Atoi(s) oppure n, _ := strconv.Atoi(s). Non puoi tralasciare del tutto un valore: il numero di variabili a sinistra deve corrispondere al numero di risultati.
Cosa sono i valori di ritorno con nome in Go?
Parametri di risultato che hanno un nome, come func split(n int) (half, rest int). Partono dai loro zero value, si possono assegnare nel corpo, e un return senza valori restituisce i loro valori attuali. Permettono anche a una funzione in defer di cambiare ciò che riceve chi chiama.
Dovrei usare i return nudi in Go?
Solo nelle funzioni brevi. Un return senza valori in una funzione lunga nasconde cosa viene restituito e rende facili i bug di shadowing. Le guide di stile di Go consigliano di dare un nome ai risultati per documentarli e di restituire valori espliciti in tutto ciò che supera poche righe.