Рекомендуемое решение для обработки ошибок на языке Go (golang)

Go
Рекомендуемое решение для обработки ошибок на языке Go (golang)

Оригинальная ссылка:woohoo.fly snow.org/2019/01/01/…
Публичный аккаунт WeChat: flysnow_org

Из-за неправильного дизайна языка Go (golang), я полагаю, многие люди столкнулись с этим.Это заставляет вызывающую сторону обрабатывать ошибку, возвращая значение, либо вы игнорируете ее, либо обрабатываете ее (обработка также может продолжать возвращаться к звонящий), для метода проектирования golang мы напишем много кода в кодеifсуждение для принятия решения.

func main() {
	conent,err:=ioutil.ReadFile("filepath")
	if err !=nil{
		//错误处理
	}else {
		fmt.Println(string(conent))
	}
}

Этот тип кода очень распространен в нашем кодировании, в большинстве случаевerrorобаnil, то есть ошибок нет, но нетnilКогда это означает, что произошла ошибка, нам нужно с ней справиться.

интерфейс ошибки

errorПо сути интерфейс, встроенный, давайте посмотрим на его определение

// The error built-in interface type is the conventional interface for
// representing an error condition, with the nil value representing no error.
type error interface {
	Error() string
}

У него есть только один методError, пока этот метод реализован, он реализованerror. Теперь попробуем определить ошибку самостоятельно.

type fileError struct {
}

func (fe *fileError) Error() string {
	return "文件错误"
}

пользовательская ошибка

пользовательскийfileErrorТип, реализованныйerrorинтерфейс. Теперь протестируйте его, чтобы увидеть эффект.

func main() {
	conent, err := openFile()
	if err != nil {
		fmt.Println(err)
	} else {
		fmt.Println(string(conent))
	}
}

//只是模拟一个错误
func openFile() ([]byte, error) {
	return nil, &fileError{}
}

Мы запускаем смоделированный код и видим文件错误объявление о.

В реальном использовании мы можем столкнуться со многими ошибками. Разница между ними заключается в том, что информация об ошибке отличается. Один из способов — определить тип ошибки для каждой ошибки, как указано выше, но это слишком хлопотно. мы обнаруживаемErrorТо, что возвращается, на самом деле является строкой, мы можем изменить ее, чтобы можно было установить строку.

type fileError struct {
	s string
}

func (fe *fileError) Error() string {
	return fe.s
}

Что ж, после этого преобразования мы можем объявитьfileErrorПри настройке текста ошибки, который будет запрашиваться, он может удовлетворить наши различные потребности.

//只是模拟一个错误
func openFile() ([]byte, error) {
	return nil, &fileError{"文件错误,自定义"}
}

Что ж, да, мы достигли своей цели. Теперь мы можем сделать его более общим, например, изменитьfileErrorИмя, а затем создайте функцию помощника, чтобы мы могли создавать разные типы ошибок.

//blog:www.flysnow.org
//wechat:flysnow_org
func New(text string) error {
	return &errorString{text}
}

type errorString struct {
	s string
}

func (e *errorString) Error() string {
	return e.s
}

Стать выше, мы можем пройтиNewфункция, чтобы помочь нам создавать различные ошибки, которые мы часто используемerrors.NewФункция была разработана нашим анализом шаг за шагом.Теперь все ошибаются по поводу встроенных ошибок языка Go (golang).errorС четким пониманием.

существующие проблемы

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

Также, например, мы хотимerrorДобавьте дополнительную информацию, а затем вернитесь, например, как в приведенном выше примере, как мы это делаем? мы можем только пройтиErrorметод, выньте исходное сообщение об ошибке, затем соедините его самостоятельно, а затем используйтеerrors.NewФункция генерирует новый возврат ошибки.

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

Решать проблему

Если мы хотим решить вышеуказанные проблемы, то сначала мы должны продолжать расширять нашиerrorStringи добавьте еще несколько полей для хранения дополнительной информации. Например, мы хотим записать информацию о стеке.

type stack []uintptr
type errorString struct {
	s string
	*stack
}

Добро пожаловать в публичный аккаунт WeChatflysnow_orgили сайт блогаwww.flysnow.org/Ознакомьтесь с другими оригинальными статьями.

С информацией о стеке хранилищаstackПоле, когда мы создаем ошибку, мы можем хранить информацию стека вызовов в этом поле.

//blog:www.flysnow.org
//wechat:flysnow_org

func callers() *stack {
	const depth = 32
	var pcs [depth]uintptr
	n := runtime.Callers(3, pcs[:])
	var st stack = pcs[0:n]
	return &st
}

func New(text string) error {
	return &errorString{
		s:   text,
		stack: callers(),
	}
}

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

type withMessage struct {
	cause error
	msg   string
}

func WithMessage(err error, message string) error {
	if err == nil {
		return nil
	}
	return &withMessage{
		cause: err,
		msg:   message,
	}
}

использоватьWithMessageфункция, для оригиналаerrorПод упаковкой может появиться новая ошибка с информацией об упаковке.

Рекомендуемое решение

Мы решаем проблему выше, принятый метод более знаком? Особенно глядя на исходный код, да, этоgithub.com/pkg/errorsИсходный код для этой библиотеки обработки ошибок.

Поскольку ошибки, предоставляемые языком Go, настолько просты, что мы не можем лучше справиться с проблемами или даже предоставить нам более полезную информацию для обработки ошибок, поэтому было создано так много библиотек для обработки ошибок.github.com/pkg/errorsОн относительно прост и обладает очень мощными функциями, что было одобрено большим количеством разработчиков и многими пользователями.

Его использование очень простое, если мы хотим сгенерировать новую ошибку, мы можем использоватьNewФункция, вызвавшая ошибку, имеет собственную информацию о стеке вызовов.

func New(message string) error

Если есть существующийerror, нам нужно снова его завернуть, на этот раз на выбор три функции.

//只附加新的信息
func WithMessage(err error, message string) error

//只附加调用堆栈信息
func WithStack(err error) error

//同时附加堆栈和信息
func Wrap(err error, message string) error

На самом деле приведенная выше упаковка очень похожа на упаковку исключений в Java.error, по фактуCause, основной причиной ошибки, упомянутой в предыдущей главе, являетсяCause. Итак, эта библиотека обработки ошибок предоставляет намCauseФункции позволяют нам добраться до основной причины ошибки.

func Cause(err error) error {
	type causer interface {
		Cause() error
	}

	for err != nil {
		cause, ok := err.(causer)
		if !ok {
			break
		}
		err = cause.Cause()
	}
	return err
}

использоватьforЦикл продолжает находить самый фундаментальный (нижний)error.

Мы упаковали и собрали вышеуказанные ошибки, так как же нам распечатать такую ​​информацию, как стек, хранящийся в них, причину ошибки и т.д.? На самом деле типы ошибок этой библиотеки обработки ошибок реализованыFormatterинтерфейс, мы можем пройтиfmt.PrintfФункция выводит соответствующее сообщение об ошибке.

%s,%v //功能一样,输出错误信息,不包含堆栈
%q //输出的错误信息带引号,不包含堆栈
%+v //输出错误信息和堆栈

Если выше указан тип ошибки переноса цикла, эти ошибки будут выведены рекурсивно.

резюме

с помощью этогоgithub.com/pkg/errorsБиблиотека ошибок, мы можем собрать больше информации, может облегчить нам поиск проблемы.

Собранную нами информацию можно не только выводить в консоль, но и использовать в виде лога, используя вывод в соответствующийLogЖурнал для легкого анализа проблемы.

Говорят, что эта библиотека будет добавлена ​​в стандартный SDK Golang. Я с нетерпением жду этого. Если она будет добавлена, она должна быть дополнением к текущей стандартной библиотеке.errorsэтот пакет.

Эта статья является оригинальной статьей, перепечатайте и укажите источник, добро пожаловать на сканирование кода и обратите внимание на общедоступный номерflysnow_orgили сайт asfwww.flysnow.org/, и впервые прочитал последующие замечательные статьи. Если вы считаете, что это хорошо, пожалуйста, нажмите «красивый» в правом нижнем углу статьи, спасибо за вашу поддержку.

扫码关注