分享
  1. 首页
  2. 文章

Golang全面深入系列之 Error

90design · · 4169 次点击 · · 开始浏览
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

What you are wasting today is tomorrow for those who died yesterday; what you hate now is the future you can not go back.

你所浪费的今天是昨天死去的人奢望的明天; 你所厌恶的现在是未来的你回不去的曾经。

Go errors简介

在Go的惯用法中,返回值不是整型等常用返回值类型,而是用了一个 error(interface类型)。

// 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
}

就像任何其他内置类型,如int,float64一样......错误值可以存储在变量中,从函数返回等等。

ackage main
import ( 
 "fmt"
 "os"
)
func main() { 
 f, err := os.Open("/test.txt")
 if err != nil {
 fmt.Println(err)
 return
 }
 fmt.Println(f.Name(), "opened successfully")
}

如果文件test.txt不存在, Open方法会返回error.

在go中处理错误的惯用方式是将返回的错误与nil进行比较。零值表示没有发生错误,而非零值表示存在错误。在上面的例子中,我们检查错误是否不为nil。如果不是,我们只需打印错误并从主函数返回。

错误类型定义

type error interface { 
 Error() string
}

我们知道,golang中 error的定义是一个接口类型, 任何实现此接口的类型都可以用作错误的输出调用。此方法提供错误的描述。当打印错误时,fmt.println函数在内部调用Error()字符串方法来获取错误的描述。

从错误中提取更多信息的不同方式

现在我们知道error是一种接口类型,可以让我们看看如何提取更多有关的错误信息。例如:上面例子中,我们想提取导致错误的文件路径该如何获取?

1.声明底层结构类型并从结构字段获取更多信息

如果仔细阅读open函数的文档,可以看到它返回了类型*Patherror的错误。Patherror是一个结构类型

Open方法的实现:

func Open(name string) (*File, error) {
	return OpenFile(name, O_RDONLY, 0)
}

OpenFile方法的实现:

// OpenFile is the generalized open call; most users will use Open
// or Create instead. It opens the named file with specified flag
// (O_RDONLY etc.) and perm, (0666 etc.) if applicable. If successful,
// methods on the returned File can be used for I/O.
// If there is an error, it will be of type *PathError.
func OpenFile(name string, flag int, perm FileMode) (*File, error) {
	if name == "" {
		return nil, &PathError{"open", name, syscall.ENOENT}
	}
	r, errf := openFile(name, flag, perm)
	if errf == nil {
		return r, nil
	}
	r, errd := openDir(name)
	if errd == nil {
		if flag&O_WRONLY != 0 || flag&O_RDWR != 0 {
			r.Close()
			return nil, &PathError{"open", name, syscall.EISDIR}
		}
		return r, nil
	}
	return nil, &PathError{"open", name, errf}
}

其中发生错误都返回了*PathError这个结构体实例。那么我们来看看这个结构体的具体信息。

// PathError records an error and the operation and file path that caused it.
type PathError struct {
	Op string
	Path string
	Err error
}
func (e *PathError) Error() string { return e.Op + " " + e.Path + ": " + e.Err.Error() }

此结构体实现了error接口。 结构体元素中也包括了Path的相关信息。

那么我们修改一上示例的代码:

package main
import (
	"fmt"
	"os"
)
func main() {
	f, err := os.Open("/test.txt")
	if errObject, ok := err.(*os.PathError); ok {
		fmt.Println("错误输出:",err, "文件路径:", errObject.Path)
		return
	}
	fmt.Println(f.Name(), "opened successfully")
}

此时的errObject就是PathError的一个实例。

现在,我们已成功使用类型断言来从错误中获取文件路径。

2.声明底层结构类型并使用方法获取更多信息

通过调用结构类型的方法来断言底层类型并获取更多信息。

让我们通过一个例子来更好地理解这一点。标准库中的DNSError结构类型定义如下,

type DNSError struct { 
 ...
}
func (e *DNSError) Error() string { 
 ...
}
func (e *DNSError) Timeout() bool { 
 ... 
}
func (e *DNSError) Temporary() bool { 
 ... 
}

从上面的代码可以看出,DNSError结构有两个方法timeout()bool和temporary()bool,它们返回一个布尔值,表示错误是由于超时还是临时性的。

package main
import (
	"fmt"
	"net"
)
func main() {
	addr, err := net.LookupHost("wwwwwwwwww.xxxx")
	if err, ok := err.(*net.DNSError); ok {
		if err.Timeout() {
			fmt.Println("operation timed out")
		} else if err.Temporary() {
			fmt.Println("temporary error")
		} else {
			fmt.Println("generic error: ", err)
		}
		return
	}
	fmt.Println(addr)
}

程序会输出:generic error: lookup wwwwwwwwww.xxxx: no such host, 我们就可以确定错误既不是暂时性的,也不是由于超时。

3.直接比较

package main
import ( 
 "fmt"
 "path/filepath"
)
func main() { 
 files, error := filepath.Glob("[")
 if error != nil && error == filepath.ErrBadPattern {
 fmt.Println(error)
 return
 }
 fmt.Println("matched files", files)
}

如果Glob()的模式错误,就会报ErrBadPattern的错误类型。

最后一点:

永远不要忽略错误

记住!!!多写一点小麻烦,省掉千千万万个大麻烦!!!

最后,写的有点匆忙,有错误之处还望指正!


有疑问加站长微信联系(非本文作者)

本文来自:开源中国博客

感谢作者:90design

查看原文:Golang全面深入系列之 Error

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

关注微信
4169 次点击 ∙ 1 赞
暂无回复
添加一条新回复 (您需要 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传

用户登录

没有账号?注册
(追記) (追記ここまで)

今日阅读排行

    加载中
(追記) (追記ここまで)

一周阅读排行

    加载中

关注我

  • 扫码关注领全套学习资料 关注微信公众号
  • 加入 QQ 群:
    • 192706294(已满)
    • 731990104(已满)
    • 798786647(已满)
    • 729884609(已满)
    • 977810755(已满)
    • 815126783(已满)
    • 812540095(已满)
    • 1006366459(已满)
    • 692541889

  • 关注微信公众号
  • 加入微信群:liuxiaoyan-s,备注入群
  • 也欢迎加入知识星球 Go粉丝们(免费)

给该专栏投稿 写篇新文章

每篇文章有总共有 5 次投稿机会

收入到我管理的专栏 新建专栏