Объединить несколько строк ошибок
Я новичок в 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