Zwracanie więcej niż jednej wartości
Wymień typy wyników w nawiasach. Zwracaj wartości oddzielone przecinkami i odbieraj je w ten sam sposób.
Wbudowane min i max istnieją od Go 1.21. Kod wywołujący musi odebrać każdy wynik: x := minMax(nums) się nie kompiluje i zgłasza assignment mismatch: 1 variable but minMax returns 2 values.
Konwencja (value, error)
Najczęstszy powód zwracania dwóch wartości to zgłaszanie niepowodzenia. Zgodnie z konwencją błąd jest ostatni, a gdy nie jest nil, pozostałe wyniki należy traktować jako pozbawione znaczenia.
Wynik:
port: 8080
error: port "http": strconv.Atoi: parsing "http": invalid syntax
error: port out of range
Przy niepowodzeniu zwracaj wartość zerową dla każdego innego wyniku (0, "", nil). Pełny wzorzec, łącznie z opakowywaniem i sprawdzaniem, jest na stronie o obsłudze błędów.
Idiom comma-ok
Kilka wbudowanych operacji zwraca opcjonalny drugi bool, który mówi, czy pierwsza wartość jest prawdziwa. Zmienną zwyczajowo nazywa się ok.
Te trzy formy (odczyt z mapy, asercja typu, odbiór z kanału) są wyjątkowe: zwracają jedną lub dwie wartości w zależności od tego, do ilu zmiennych je przypisujesz. Twoje własne funkcje tak nie potrafią. Funkcja zadeklarowana z dwoma wynikami zawsze zwraca dwa.
Pusty identyfikator
_ odbiera wartość i ją wyrzuca. Używaj go dla wyników, których nie potrzebujesz:
_, err := fmt.Sscan(input, &n)
key, _ := parseLine(line)
Zignorowanie błędu przez _ się kompiluje, więc rób to tylko wtedy, gdy wiesz, że wywołanie nie może zawieść albo niepowodzenie nie ma znaczenia. Na przykład strings.Builder.WriteString zawsze zwraca błąd nil; zamknięcie pliku po zapisie już nie.
Nazwane wyniki
Parametry wynikowe mogą mieć nazwy. Są deklarowane na początku funkcji, inicjalizowane wartościami zerowymi, a return bez wartości zwraca to, co akurat w nich jest.
Nazwy pojawiają się w wyniku go doc, co pomaga, gdy dwa wyniki mają ten sam typ: (quotient, remainder int) mówi więcej niż (int, int).
Samo return w długiej funkcji trudno się czyta, bo trzeba cofać się wzrokiem, żeby zobaczyć, co zawierają wyniki. Typowa rada: nazywaj wyniki, gdy nazwy coś dokumentują, a mimo to pisz jawnie return quotient, remainder, chyba że funkcja ma kilka linii.
Nazwane wyniki i defer
Funkcja odroczona wykonuje się po tym, jak instrukcja return ustawi wyniki, a zanim otrzyma je kod wywołujący. Przy nazwanych wynikach funkcja odroczona może je odczytać i zmienić. W ten sposób dodaje się kontekst do każdego błędu zwracanego przez funkcję albo zamienia panikę w błąd.
To wypisuje load : empty name, a potem <nil>. return errors.New(...) najpierw przypisuje wartość do err, a potem funkcja odroczona ją opakowuje. Więcej w artykule o defer.
Przesłanianie nazwanego wyniku
Nazwane wyniki żyją w najbardziej zewnętrznym zasięgu funkcji. := wewnątrz zagnieżdżonego bloku tworzy nową zmienną o tej samej nazwie, a samo return zwraca wtedy tę zewnętrzną.
func find() (n int, err error) {
if true {
n, err := compute() // new n and err, shadowing the results
_ = n
_ = err
}
return // returns 0, nil
}
Kompilator wyłapuje najgorszy przypadek: samo return wewnątrz bloku, w którym wynik jest przesłonięty, kończy się błędem result parameter err not in scope at return. Nie wyłapuje wersji powyżej, gdzie return stoi poza blokiem. Używaj = zamiast :=, gdy chodzi ci o zmienne wynikowe.
Częste błędy
- Używanie wartości, gdy err nie jest nil. Najpierw sprawdź
err. Funkcja może razem z błędem zwrócić cokolwiek. - Zwracanie typowanego wskaźnika nil jako błędu.
var e *MyErr; return ezwracaerror, który nie jest nil. Przy sukcesie zwracaj dosłownenil. - Zbyt wiele wyników. Trzy lub więcej wyników o różnym znaczeniu trudno używać. Zwróć zamiast tego strukturę.
Najczęściej zadawane pytania
Jak zwrócić wiele wartości z funkcji w Go?
Wymień typy wyników w nawiasach i zwróć wartości oddzielone przecinkami: func minMax(xs []int) (int, int) { ...; return lo, hi }. Kod wywołujący przypisuje je wszystkie naraz: lo, hi := minMax(nums).
Jak w Go zignorować jedną z wartości zwracanych?
Przypisz ją do pustego identyfikatora _: _, err := strconv.Atoi(s) albo n, _ := strconv.Atoi(s). Nie można całkiem pominąć wartości: liczba zmiennych po lewej stronie musi się zgadzać z liczbą wyników.
Czym są nazwane wartości zwracane w Go?
To parametry wynikowe z nazwami, np. func split(n int) (half, rest int). Startują z wartościami zerowymi, można je przypisywać w ciele funkcji, a samo return zwraca ich bieżące wartości. Pozwalają też funkcji odroczonej zmienić to, co dostanie kod wywołujący.
Czy w Go używać gołego return?
Tylko w krótkich funkcjach. Samo return w długiej funkcji ukrywa, co jest zwracane, i ułatwia błędy z przesłanianiem. Przewodniki stylu Go zalecają nazywanie wyników dla dokumentacji i jawne zwracanie wartości we wszystkim, co ma więcej niż kilka linii.