Menu

If else w Go: składnia, if z inicjalizacją i if err != nil

Jak działają if, else if i else w Go: bez nawiasów, z obowiązkowymi klamrami, if z instrukcją inicjującą i jej zasięg, idiom if err != nil i wczesne powroty zamiast głębokiego zagnieżdżania.

Na tej stronie są działające edytory: edytuj, uruchamiaj i od razu zobacz wynik.

if w Go nie ma nawiasów wokół warunku, zawsze wymaga klamer i może zaczynać się od krótkiej instrukcji, która deklaruje zmienne o zasięgu ograniczonym do tego if.

Warunki są sprawdzane od góry i wykonuje się pierwsza prawdziwa gałąź. else if i else są opcjonalne.

Zasady składni

Trzy zasady różnią się od C, Javy i JavaScriptu:

  1. Brak nawiasów wokół warunku. if (x > 5) się kompiluje, ale gofmt usuwa nawiasy.
  2. Klamry są obowiązkowe, nawet dla jednej instrukcji. Nie istnieje if x > 5 return bez klamer.
  3. else stoi w tej samej linii co klamra zamykająca. Go wstawia średnik po } na końcu linii, więc to nie działa:
if x > 5 {
	fmt.Println("big")
}
else {
	fmt.Println("small")
}
syntax error: unexpected keyword else, expected }

Pisz } else { w jednej linii.

Warunek musi być typu bool. Go nie traktuje 0, "" ani nil jako fałszu, więc if count {} i if name {} się nie kompilują. Porównuj jawnie: if count > 0, if name != "", if user != nil.

Łącz warunki przez && (i), || (lub) i ! (nie). Zarówno &&, jak i || działają na skróty, dzięki czemu sprawdzanie nil jest bezpieczne:

if user != nil && user.IsAdmin() {
	// user.IsAdmin() is only called when user is not nil
}

if z instrukcją inicjującą

if może wykonać jedną krótką instrukcję przed warunkiem, oddzieloną średnikiem. Zadeklarowane w niej zmienne są widoczne w każdej gałęzi tego if, a nigdzie za nim:

Ten wzorzec trzyma krótkotrwałe zmienne z dala od otaczającego zasięgu. Pojawia się bez przerwy przy odczycie z mapy (v, ok := m[k]), asercjach typu (s, ok := v.(string)) i błędach.

Druga strona medalu: jeśli potrzebujesz wartości za if, zadeklaruj ją wcześniej. Częsty błąd to umieszczenie wyniku w instrukcji inicjującej, a potem próba użycia go niżej.

Idiom if err != nil

Funkcje, które mogą zawieść, zwracają error na końcu. Sprawdź go od razu, obsłuż lub zwróć i kontynuuj szczęśliwą ścieżkę bez wcięcia:

Zwróć uwagę, że po if err != nil { return ... } nie ma else. Styl Go to obsłużyć błąd, zwrócić i zostawić normalny przepływ przy lewym marginesie. Strona o obsłudze błędów opisuje opakowywanie błędów i sprawdzanie ich typów.

Wczesne powroty zamiast zagnieżdżania

Głęboko zagnieżdżone bloki if trudno się czyta. Odwróć warunki i wracaj wcześnie; każde sprawdzenie czyta się wtedy jak strażnik:

// Nested
func canCheckout(u *User, cart *Cart) bool {
	if u != nil {
		if u.Verified {
			if len(cart.Items) > 0 {
				return true
			}
		}
	}
	return false
}

// Guards
func canCheckout(u *User, cart *Cart) bool {
	if u == nil || !u.Verified {
		return false
	}
	if len(cart.Items) == 0 {
		return false
	}
	return true
}

Programiści Go nazywają to trzymaniem szczęśliwej ścieżki przy lewej krawędzi. Lintery, takie jak revive, zgłaszają else po bloku kończącym się return, bo takie else dodaje wcięcie bez żadnej korzyści.

if/else a switch

Długi łańcuch else if, który porównuje jedną wartość z kilkoma przypadkami, czyta się lepiej jako switch. switch bez wyrażenia zastępuje łańcuch if/else if z dowolnymi warunkami:

switch {
case score >= 90:
	return "A"
case score >= 80:
	return "B"
default:
	return "F"
}

Używaj if dla jednej lub dwóch gałęzi, a switch, gdy jest ich trzy lub więcej.

Brak operatora trójargumentowego

Go nie ma cond ? a : b. Przypisz wartość przez if:

label := "odd"
if n%2 == 0 {
	label = "even"
}

Strona o operatorze trójargumentowym wyjaśnia dlaczego i pokazuje alternatywy.

Częste błędy

  • Przesłanianie przez :=. if x, err := f(); err == nil { ... } deklaruje nowe x tylko dla if. Zewnętrzne x nie zostaje zaktualizowane.
  • Przypisanie w warunku. if x = 5 {} to błąd kompilacji (cannot use assignment x = 5 as value), a nie cichy błąd jak w C. Użyj ==.
  • Porównywanie liczb zmiennoprzecinkowych przez ==. if total == 0.3 zawodzi dla obliczonych wartości. Porównuj z tolerancją.
  • Sprawdzanie niewłaściwego błędu. Po a, err := f() i b, err := g() upewnij się, że każde if err != nil stoi zaraz po swoim wywołaniu.

Najczęściej zadawane pytania

Jak napisać if else w Go?

Bez nawiasów wokół warunku i zawsze z klamrami:

if x > 10 {
	fmt.Println("big")
} else if x > 5 {
	fmt.Println("medium")
} else {
	fmt.Println("small")
}

else musi być w tej samej linii co klamra zamykająca poprzedni blok.

Czym jest if z instrukcją inicjującą w Go?

To krótka instrukcja przed warunkiem, oddzielona średnikiem: if n, err := strconv.Atoi(s); err != nil { ... }. Zadeklarowane w niej zmienne istnieją tylko wewnątrz if i jego gałęzi else if oraz else, dzięki czemu nie wyciekają do reszty funkcji.

Czy w Go można napisać if w jednej linii?

Nie bez klamer. if ok return i if (ok) x = 1; to błędy składni. Najkrótsza forma to if ok { return }, a gofmt przenosi ciało do osobnej linii. Go nie ma też operatora trójargumentowego, więc wartość zależna od warunku wymaga if/else albo małej funkcji pomocniczej.

Dlaczego w Go wszędzie jest if err != nil?

Go nie ma wyjątków. Funkcje, które mogą zawieść, zwracają error jako ostatni wynik, a kod wywołujący od razu go sprawdza przez if err != nil. To powtarzanie jest ceną za to, że każde miejsce możliwej awarii jest widoczne tam, gdzie występuje.

Ilustracja języków programowania w Coddy

Ucz się programowania z Coddy

ZACZNIJ