Errors

Помилки (Errors)|Errors #

// Одна з ідіом Go, це отримувати `помилки` що повертаються (з функцій)
// разом з іншими даними. Це виділяє Go на тлі мов що використовують
// _виключення_ (_exceptions_) - Java, Ruby та інше, або в порівнянні
// з перевантаженням одиночного результату та помилки, що інколи
// використовується в С. Підхід Go, полегшує нагляд за функціями,
// що повертають помилки і опрацьовують їх (помилки) - так само,
// як і інші, не-помилкові, задачі.

package main

import (
	"errors"
	"fmt"
)

// За погодженням, помилкою вказується останнє,
// з значень що повертається, що, на додачу має тип
// `error` (який є вбудованим інтерфейсом).
func f1(arg int) (int, error) {
	if arg == 42 {
		// Конструкція `errors.New` створює базове значення
		// помилки з заданим повідомленням.
		return -1, errors.New("can't work with 42")
	}

	// А `nil` значення на позиції помилки - вказує на те,
	// що ніякої помилки не виникло.
	return arg + 3, nil
}

// Можливо використовувати і інші типи як помилки (`error`s)
// (тільки - якщо ці типи реалізують метод `Error()` на собі,
// тобто імплементують інтерфейс помилки).
// Ось приклад, що використовує власний тип помилки, яка
// репрезентує `помилку` значення переданого аргументом.
type argError struct {
	arg  int
	prob string
}

func (e *argError) Error() string {
	return fmt.Sprintf("%d - %s", e.arg, e.prob)
}

func f2(arg int) (int, error) {
	if arg == 42 {
		// У цьому випадку ми використовуємо синтакс `&argError`
		// щоб створити нову структуру - забезпечивши її значеннями
		// для двох полів `arg` та `prob`.
		return -1, &argError{arg, "can't work with it"}
	}
	return arg + 3, nil
}

func main() {

	// Ци два цикли тестують кожну з наших функцій (що повертають
	// помилки), зауважте, що перевірка помилки, що проводиться
	// поряд з оператором умовного розгалуження `if`,
	// це одна з ідіом Go.
	for _, i := range []int{7, 42} {
		if r, e := f1(i); e != nil {
			fmt.Println("f1 failed:", e)
		} else {
			fmt.Println("f1 worked:", r)
		}
	}
	for _, i := range []int{7, 42} {
		if r, e := f2(i); e != nil {
			fmt.Println("f2 failed:", e)
		} else {
			fmt.Println("f2 worked:", r)
		}
	}

	// Якщо ви хочете скористатись даними вашої помилки програмно -
	// необхідно дістати помилку як зразок (instance) вашого
	// типу, використовуючи заяву типу (type assertion).
	_, e := f2(42)
	if ae, ok := e.(*argError); ok {
		fmt.Println(ae.arg)
		fmt.Println(ae.prob)
	}
}
$ go run errors.go
f1 worked: 10
f1 failed: can't work with 42
f2 worked: 10
f2 failed: 42 - can't work with it
42
can't work with it

# Як завжди, трошка докаладнішу інформацію про помилки
# можна знайти в [записах](http://blog.golang.org/2011/07/error-handling-and-go.html)
# блогу команди розробників Go.