Go в примери: Грешки

Обичайно1 в Го грешките се съобщават изрично чрез връщане на отделна сойност. Това е съвсем различен подход в сравнение с езици като Java, Python и Ruby и презареденият2 единичен изход3 / грешка, ползван понякога в C.

С този подход Го прави по-лесно да се видят функциите, които връщат грешки и да се обработват грешките по същия начин както и другите стойности, ползвани за други задачи.

Вижте документацията на пакета errors и тази статия за повече подробности.


  1. idiomatic – обичайно, като начин на изразяване и мислене в някакъв език
  2. overload – презареждам
  3. result – изход (от действие)
package main
import (
    "errors"
    "fmt"
)

Обичайно1 грешките са последната върната стойност и са от вида error, който е описано и осъществено в пакета взаимодействие.


  1. by convention – обичайно, по взаимно съгласие в някаква общност
func f(arg int) (int, error) {
    if arg == 42 {

errors.New съставя обикновена стойност от вида error с дадено съобщение за грешка.

        return -1, errors.New("не мога да работя с 42")
    }

Стойност nil на мястото на грешката означава, че няма грешка.

    return arg + 3, nil
}

Предпазната грешка1 представлява предварително обявена променлива, която се използва, за да обозначи грешка, случила се при определени условия.


  1. sentinel error – предпазна грешка (като предпазен клапан)
var ErrOutOfTea = errors.New("няма повече чай")
var ErrPower = errors.New("не мога да сваря вода")
func makeTea(arg int) error {
    if arg == 2 {
        return ErrOutOfTea
    } else if arg == 4 {

Можем да обгърнем1 грешките в други грешки от по-високо равнище, за да добавим смисъл2. Най-простият начин да го направим е с помощта на глагола %w в fmt.Errorf. Обгърнатите грешки създават смислова логическа верига (А обгръща Б, която обгръща В, и т.н.), която може да бъде проследявана с функции като errors.Is и errors.AsType.


  1. wrap – обгръщам, увивам като пакет, загръщам.
  2. context – смисъл.
        return fmt.Errorf("правя чай: %w", ErrPower)
    }
    return nil
}
func main() {
    for _, i := range []int{7, 42} {

В Го обичайно се прави проверка направо в реда с условието – след if

        if r, e := f(i); e != nil {
            fmt.Println("f не проработи:", e)
        } else {
            fmt.Println("f проработи:", r)
        }
    }
    for i := range 5 {
        if err := makeTea(i); err != nil {

errors.Is проверява дали дадена грешка (или всяка грешка по веригата ѝ) съвпада с опредлена стойсност. Това е особено полезно при обгърнати или вгнездени една в друга грешки и ви позволява да разпознаете определени видове грешки или предпазни грешки по веригата.

            if errors.Is(err, ErrOutOfTea) {
                fmt.Println("Трябва да си купим чай!")
            } else if errors.Is(err, ErrPower) {
                fmt.Println("Сега е тъмно.")
            } else {
                fmt.Printf("непозната грешка: %s\n", err)
            }
            continue
        }
        fmt.Println("Чаят е готов!")
    }
}
$ go run errors.go
f проработи: 10
f не проработи: не мога да работя с 42
Чаят е готов!
Чаят е готов!
Трябва да си купим чай!
Чаят е готов!
Сега е тъмно.

Следващ пример: .