Объединить несколько строк ошибок

Я новичок в golang, мое приложение должно возвращать несколько ошибок в цикле, а затем требует объединения и возврата в виде одной строки ошибки. Я не могу использовать строковые функции для объединения сообщений об ошибках. Какие методы можно использовать для объединения этих ошибок в одну ошибку перед возвратом?

package main

import (
   "fmt"
   "strings"
)

func Servreturn() (err error) {

   err1 = fmt.Errorf("Something else occured")
   err2 = fmt.Errorf("Something else occured again")

   // concatenate both the error

   return err3

}

Ответ 1

Вы можете использовать функции strings.Join() и append() для получения этого фрагмента.

пример: golang playgorund

package main

import (
    "fmt"
    "strings"
    "syscall"
)

func main() {

    // create a slice for the errors
    var errstrings []string 

    // first error
    err1 := fmt.Errorf("First error:server error")
    errstrings = append(errstrings, err1.Error())

    // do something 
    err2 := fmt.Errorf("Second error:%s", syscall.ENOPKG.Error())
    errstrings = append(errstrings, err2.Error())

    // do something else
    err3 := fmt.Errorf("Third error:%s", syscall.ENOTCONN.Error())
    errstrings = append(errstrings, err3.Error())

    // combine and print all the error
    fmt.Println(fmt.Errorf(strings.Join(errstrings, "\n")))


}

Это выводит одну строку, которую вы можете отправить обратно клиенту.

First error:server1 
Second error:Package not installed 
Third error:Socket is not connected

надеюсь, что это поможет!

Ответ 2

Строковые функции не работают с ошибками, потому что ошибка на самом деле является интерфейсом, реализующим функцию Error() string.

Вы можете использовать строковые функции для err1.Error() и err2.Error() но не на самой ошибке "err1".

Некоторые ошибки представляют собой структуры, такие как те, которые вы получаете из драйверов баз данных.

Таким образом, нет естественного способа использования строковых функций для ошибок, поскольку они могут не быть строками внизу.

Что касается объединения двух ошибок:

Просто, просто используйте fmt.Errorf снова.

fmt.Errorf("Combined error: %v %v", err1, err2)

В качестве альтернативы:

errors.New(err1.Error() + err2.Error())

Ответ 3

Чтобы расширить то, что @WillC упомянул в комментарии, можно определить свой собственный тип error, так как error является типом интерфейса. Любой тип, который реализует функцию Error() string, реализует интерфейс error. Следовательно, вы можете создать CollectionError, который агрегирует ошибки и возвращает объединенную строку ошибок.

type ErrorCollector []error

func (c *ErrorCollector) Collect(e error) { *c = append(*c, e) }

func (c *ErrorCollector) Error() (err string) {
    err = "Collected errors:\n"
    for i, e := range *c {
        err += fmt.Sprintf("\tError %d: %s\n", i, e.Error())
    }

    return err
}

Это обеспечивает функцию сбора, которая добавляет данный error к срезу. После вызова Error() string он выполняет итерации по срезу и создает объединенную строку ошибок.

func main() {
    collector := new(ErrorCollector)

    for i := 0; i < 10; i++ {
         collector.Collect(errors.New(fmt.Sprintf("%d Error", i)))
    }

    fmt.Println(collector)
}

В великолепном блоге более подробно рассматриваются ошибки. Полный пример этого примера доступен на игровой площадке Go.

Ответ 4

ОБНОВЛЕНИЕ для Go 1.13:

Начиная с версии Go версии 1.13 языковой пакет ошибок теперь напрямую поддерживает перенос ошибок.

Вы можете обернуть ошибку, используя глагол %w в fmt.Errorf:

err := errors.New("Original error")
err = fmt.Errorf("%w; Second error", err)

Используйте Развернуть, чтобы удалить последнюю добавленную ошибку и вернуть то, что осталось: previousErrors := errors.Unwrap(err)

Пример игровой площадки для ошибок. Разворачивайте

Еще две функции: errors.Is и errors.As предоставляют способы проверки и поиска определенного типа ошибки.

Пример игровой площадки для ошибок. Как и ошибки. Есть


Отличный пакет Дэйва Чейни errors (https://github.com/pkg/errors) включает функцию Wrap для этой цели:

package main

import "fmt"
import "github.com/pkg/errors"

func main() {
        err := errors.New("error")
        err = errors.Wrap(err, "open failed")
        err = errors.Wrap(err, "read config failed")

        fmt.Println(err) // "read config failed: open failed: error"
}

Это также позволяет использовать дополнительные функции, такие как распаковка причины ошибки:

package main

import "fmt"
import "github.com/pkg/errors"

func main() {
    err := errors.New("original error")
    err = errors.Wrap(err, "now this")

    fmt.Println(errors.Cause(err)) // "original error"
}

А также возможность вывода трассировки стека при указании fmt.Printf("%+v\n", err).

Вы можете найти дополнительную информацию о пакете в его блоге: здесь и здесь.

Ответ 5

Люди могут быть заинтересованы в https://github.com/hashicorp/go-multierror, который описывает себя как пакет A Go (golang) для представления списка ошибок как единственная ошибка. ".

Ответ 6

Используйте эту функцию:

func JoinErrs(errs ...error) error {
    var joinErrsR func(string, int, ...error) error
    joinErrsR = func(soFar string, count int, errs ...error) error {
        if len(errs) == 0 {
            if count == 0 {
                return nil
            }
            return fmt.Errorf(soFar)
        }
        current := errs[0]
        next := errs[1:]
        if current == nil {
            return joinErrsR(soFar, count, next...)
        }
        count++
        if count == 1 {
            return joinErrsR(fmt.Sprintf("%s", current), count, next...)
        } else if count == 2 {
            return joinErrsR(fmt.Sprintf("1: %s\n2: %s", soFar, current), count, next...)
        }
        return joinErrsR(fmt.Sprintf("%s\n%d: %s", soFar, count, current), count, next...)
    }
    return joinErrsR("", 0, errs...)
}

Это даст вам ноль, когда все ошибки равны нулю, даст вам ту же ошибку, когда только одна ошибка не ноль, даст вам нумерованный список ошибок не ноль, когда несколько ошибок не ноль

Попробуйте это здесь: https://play.golang.org/p/WttztCr-xHG