既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上Go语言开发知识点,真正体系化!
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新
下面首先说说如何创建 error
。
创建 error
有两种方式,分别是:
-
errors.New()
; -
fmt.Errorf()
。
errors.New()
errors.New()
的使用延续了 Go 的一贯风格,New
一下就可以了。
举一个例子:
package main
import (
“errors”
“fmt”
)
func main() {
err := errors.New(“这是 errors.New() 创建的错误”)
fmt.Printf(“err 错误类型:%T,错误为:%v\n”, err, err)
}
/* 输出
err 错误类型:*errors.errorString,错误为:这是 errors.New() 创建的错误
*/
这段代码唯一让人困惑的地方可能就是错误类型了,但没关系。只要看一下源码,就瞬间迎刃而解。
源码如下:
// src/errors/errors.go
// New returns an error that formats as the given text.
// Each call to New returns a distinct error value even if the text is identical.
func New(text string) error {
return &errorString{text}
}
// errorString is a trivial implementation of error.
type errorString struct {
s string
}
func (e *errorString) Error() string {
return e.s
}
可以看到,errorString
是一个结构体,实现了 Error()
方法,New
函数直接返回 errorString
指针。
这种用法很简单,但不实用。假如我还想返回程序的上下文信息,它就没辙了。
下面看第二种方式。
fmt.Errorf()
还是先看一个例子:
package main
import (
“database/sql”
“fmt”
)
func foo() error {
return sql.ErrNoRows
}
func bar() error {
return foo()
}
func main() {
err := bar()
if err == sql.ErrNoRows {
fmt.Printf(“data not found, %+v\n”, err)
return
}
if err != nil {
fmt.Println(“Unknown error”)
}
}
/* 输出
data not found, sql: no rows in result set
*/
这个例子输出了我们想要的结果,但是还不够。
一般情况下,我们会通过使用 fmt.Errorf()
函数,附加上我们想添加的文本信息,使返回内容更明确,处理起来更灵活。
所以,foo()
函数会改成下面这样:
func foo() error {
return fmt.Errorf(“foo err, %v”, sql.ErrNoRows)
}
这时问题就出现了,经过 fmt.Errorf()
的封装,原始 error
类型发生了改变,这就导致 err == sql.ErrNoRows
不再成立,返回信息变成了 Unknown error
。
如果想根据返回的 error
类型做不同处理,就无法实现了。
因此,Go 1.13 为我们提供了 wrapError
来处理这个问题。
看一个例子:
package main
import (
“fmt”
)
type myError struct{}
func (e myError) Error() string {
return “Error happended”
}
func main() {
e1 := myError{}
e2 := fmt.Errorf(“E2: %w”, e1)
e3 := fmt.Errorf(“E3: %w”, e2)
fmt.Println(e2)
fmt.Println(e3)
}
/* output
E2: Error happended
E3: E2: Error happended
*/
乍一看好像好没什么区别,但背后的实现原理却并不相同。
Go 扩展了 fmt.Errorf()
函数,增加了一个 %w
标识符来创建 wrapError
。
// src/fmt/errors.go
func Errorf(format string, a …interface{}) error {
p := newPrinter()
p.wrapErrs = true
p.doPrintf(format, a)
s := string(p.buf)
var err error
if p.wrappedErr == nil {
err = errors.New(s)
} else {
err = &wrapError{s, p.wrappedErr}
}
p.free()
return err
}
当使用 w%
时,函数会返回 &wrapError{s, p.wrappedErr}
,wrapError
结构体定义如下:
// src/fmt/errors.go
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上Go语言开发知识点,真正体系化!
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新
结构体定义如下:
// src/fmt/errors.go
[外链图片转存中…(img-jKJJs5wQ-1715398927176)]
[外链图片转存中…(img-AIUFEeD4-1715398927176)]
[外链图片转存中…(img-MoGdarAt-1715398927177)]
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上Go语言开发知识点,真正体系化!
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新