前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >错误处理

错误处理

作者头像
酷走天涯
发布2019-06-11 16:26:21
5750
发布2019-06-11 16:26:21
举报
文章被收录于专栏:每日一篇技术文章
  • 什么是错误?
  • 错误的表示
  • 获取错误详细信息的各种方法
  • 不能忽视错误

先看一个例子

代码语言:javascript
复制
package 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")
}

image.png

打开文件的函数原型如下

代码语言:javascript
复制
func Open(name string) (file *File, err error)

当我试图打开一个不存在的文件时,err 返回一个不为nil的值,如果文件存在err就会返回nil

那么 error 到底是什么?

代码语言:javascript
复制
type error interface {  
    Error() string
}

那么我们就知道了 error 就是就是一个抽象的接口,那么open 方法中的error 对应的底层结构体是什么


断言底层类型,获取更多属性
代码语言:javascript
复制
type PathError struct {  
    Op   string
    Path string
    Err  error
}

func (e *PathError) Error() string { return e.Op + " " + e.Path + ": " + e.Err.Error() }

所以我们可以将error 类型转换成 pathError 然后查看里面的具体信息

代码语言:javascript
复制
package main

import (  
    "fmt"
    "os"
)

func main() {  
    f, err := os.Open("/test.txt")
    if err, ok := err.(*os.PathError); ok {
        fmt.Println("File at path", err.Path, "failed to open")
        return
    }
    fmt.Println(f.Name(), "opened successfully")
}

断言底层类型,调用方法获取更多信息

比如请求网络,发生错误,那是由于网路超时 还是 其他原因导致的失败,我们怎么知道呢?

代码语言:javascript
复制
type DNSError struct {  
    ...
}

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

看下面代码

代码语言:javascript
复制
package main

import (
    "fmt"
    "net"
)

func main() {
    addr, err := net.LookupHost("niubi345.com")
    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)
}

image.png

这样我们就可根据不同的方法返回值来进一步判断错误类型了

直接比较

第三种获取错误的更多信息的方式,是与 error 类型的变量直接比较

看一个例子

代码语言:javascript
复制
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)
}

filepath.ErrBadPattern 是filepath 包里面的一个公开变量 如下

代码语言:javascript
复制
var ErrBadPattern = errors.New("syntax error in pattern")

errors 是什么?

image.png

errors 包中通过new 创建了一个结构体,这个结构体实现了错误接口Error()

不可忽略错误
代码语言:javascript
复制
package main

import (  
    "fmt"
    "path/filepath"
)

func main() {  
    files, _ := filepath.Glob("[")
    fmt.Println("matched files", files)
}

我们已经从前面的示例知道了这个模式是错误的。在第 9 行,通过使用 _ 空白标识符,我忽略了 Glob 函数返回的错误。我在第 10 行简单打印了所有匹配的文件。该程序会输出


自定义error 错误
代码语言:javascript
复制
// Package errors implements functions to manipulate errors.
package errors

// New returns an error that formats as the given text.
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
}

*fmt.Errorf 可以携带更多错误信息

代码语言:javascript
复制
package main

import (  
    "fmt"
    "math"
)

func circleArea(radius float64) (float64, error) {  
    if radius < 0 {
        return 0, fmt.Errorf("Area calculation failed, radius %0.2f is less than zero", radius)
    }
    return math.Pi * radius * radius, nil
}

func main() {  
    radius := -20.0
    area, err := circleArea(radius)
    if err != nil {
        fmt.Println(err)
        return
    }
    fmt.Printf("Area of circle %0.2f", area)
}
使用结构体类型和字段提供错误的更多信息

定义错类类型结构体

代码语言:javascript
复制
type areaError struct {  
    err    string
    radius float64
}

func (e *areaError) Error() string {  
    return fmt.Sprintf("radius %0.2f: %s", e.radius, e.err)
}

注意 我们是在areaError 实现的方法,所以areaError 是实现了接口,但是areaError 没有实现 所以我们使用的时候,一定要传递*areaError

如下

代码语言:javascript
复制
func circleArea(radius float64) (float64, error) {
  if radius < 0 {
     return 0, &areaError{"radius is negative", radius}
  }
     return math.Pi * radius * radius, nil
}

解析错误 需要进行数据转换

代码语言:javascript
复制
radius := -20.0
   area, err := circleArea(radius)
  if err != nil {
  if err, ok := err.(*areaError); ok {
   fmt.Printf("Radius %0.2f is less than zero", err.radius)
   return
  }
让错误类型携带更多的信息
代码语言:javascript
复制
type areaError struct {  
    err    string //error description
    length float64 //length which caused the error
    width  float64 //width which caused the error
}
func (e *areaError) Error() string {  
    return e.err
}

func (e *areaError) lengthNegative() bool {  
    return e.length < 0
}

func (e *areaError) widthNegative() bool {  
    return e.width < 0
}
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2018.12.25 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 断言底层类型,获取更多属性
  • 断言底层类型,调用方法获取更多信息
  • 直接比较
  • 不可忽略错误
  • 自定义error 错误
  • 使用结构体类型和字段提供错误的更多信息
  • 让错误类型携带更多的信息
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档