Идиоматическая обработка ошибок Голанга

Я создал базовую структуру репозитория для автономного и встроенного использования (например, с CustomerRepository), чтобы избежать необходимости постоянно проверять ошибки и создавать абстракции для Gorp (инструментария базы данных) и создавать API немного больше по душе.

Я проверяю наличие ошибок в этой базовой структуре и панике, если она найдена, как если бы она существовала, по моему мнению, она указывает на ошибку dev, и код может также паниковать, поскольку проверка и т.д. должна произойти до того, как данные будут получены в репозиторий.

Я нашел этот вопрос Go Error Handling Techniques, но он не охватывает ошибки обертывания в базовой структуре, как я это делал, и просто панику.

Это то, что я сделал с идиоматическим Go?

package repositories

import (
    "github.com/coopernurse/gorp"
)

type Repository struct {
    Gorp gorp.SqlExecutor
}

func (r *Repository) GetById(i interface{}, id int) interface{} {
    obj, err := r.Gorp.Get(i, id)
    if err != nil {
        panic(err)
    }
    return obj
}

func (r *Repository) Get(holder interface{}, query string, args ...interface{}) interface{} {
    if err := Gorp.SelectOne(holder, query, args); err != nil {
        panic(err)
    }
}

func (r *Repository) Select(i interface{}, query string, args ...interface{}) {
    if _, err := Gorp.Select(holder, query, args); err != nil {
        panic(err)
    }
}

func (r *Repository) Insert(list ...interface{}) {
    if err := r.Gorp.Insert(list...); err != nil {
        panic(err)
    }
}

func (r *Repository) Update(list ...interface{}) int64 {
    count, err := r.Gorp.Update(list...)
    if err != nil {
        panic(err)
    }
    return count
}

func (r *Repository) Delete(list ...interface{}) int64 {
    count, err := r.Gorp.Delete(list...)
    if err != nil {
        panic(err)
    }
    return count
}

Ответ 1

Идиоматическим способом было бы вернуть ошибку с соответствующим значением типа, т.е.

func (list ...interface{}) (v int46, err error) {}

... и затем проверить err!= nil, где вызывается эти функции.

В конечном итоге использование panic() приведет к обработке ошибок, подобной исключению, и коду с кодовым номером (если вы считаете ошибку, подлежащую восстановлению).

Идиоматическая обработка ошибок является многословной в Go, но меньше, чем эмуляция исключений (что принципиально не является "Go way" ).

Ответ 2

Не паникуйте, это не путь. Вместо этого сделайте что-то вроде этого -

func (r *Repository) GetById(i interface{}, id int) (interface{}, error) {
    obj, err := r.Gorp.Get(i, id)
    if err != nil {
        return nil, err
    }
    return obj, nil
}

Затем просто обработайте ошибку в вашем абоненте. Из ваших комментариев выше видно, что вы используете эти функции внутри обработчика Martini, поэтому вы бы сделали что-то вроде этого -

func MyHandler(parameters) (int, string) {
    obj, err := repository.GetById(something, id)
    if err == repository.ErrNotFound {
        return http.StatusNotFound, fmt.Sprintf("could not find by id: %d", id)
    }
    if err != nil {
        return http.StatusInternalError, err.Error()
    }
    return http.StatusOk, fmt.Printf("obj: %v", obj)
}

Это больше похоже на путь Go. Убедитесь, что r.Gorp.Get возвращает определенные ошибки, которые вы декларируете внутри своего пакета.

var ErrNotFound = errors.New("not found")

Создайте все, что имеет смысл для вашего кода.