📕
innohub
  • KEEP LEARNING
  • WebInfo
    • JS 部分运算符操作
    • javascript 中的object array
    • 错误处理以及异常捕获
    • JavaScript Bases
    • LaoZi & Confucius
  • PyInfo
    • Python3 输入与输出
    • Python3OS
    • python 修饰器的使用
    • python3 与mysql数据库连接使用实例
    • Format-specifier
    • CGI初学踩坑
    • Django 项目测试
    • Assert-info
    • 使用ngnix和uWSGI配置Django
    • write|SVN​
    • Matplotlib 基本使用
    • 重读 Python 官方文档
    • Python3 Base
    • python3 多线程
    • Python3 函数解析
    • python3 str 对象的基本操作
    • protocl buffers
    • Iterator-Generator
    • Django base
    • Decorator 2
    • Export to wheel or egg-info
    • 三. 运算、数据及逻辑
  • GoInfo
    • Info
      • Select 语句使用
      • First class function
      • Work Pools
      • StructTag
      • Go struct
      • 常用函数
      • Strings操作
      • Golang Bases
      • 数组以及切片
      • 文件操作
      • Golang 中的指针类型
      • Golang Map 类型
      • Reflection
      • 函数闭包
      • 接口
      • Panic and Recover
      • Go中的错误处理
      • 并发
      • defer usage
      • Method in golang
      • Object-oriented Programming
      • Goalng 包管理机制
  • RustInfo
    • Info
      • 包、crate、模块
      • Rust 中的错误处理
      • 智能指针
      • 泛型 generics
      • 数据布局与内存对齐
      • Functions and methods
      • 无畏并发
      • Actix-web 基本使用
      • Got from guessing game
      • 结构体的使用
      • Rust 中的函数式语言功能
      • 集合类型
      • 枚举以及模式匹配
      • Slice 类型
      • 生命周期
      • 测试
      • Rust 中的所有权
      • trait
      • 不安全 Rust
      • Format_print
      • Rust 通用编程概念
      • Macro
  • OS
    • info
      • 内存屏障 -- Part 1
      • 内存屏障 -- Part 2
      • CPU 上下文切换
      • 文件读写与零拷贝
      • ELF 文件
  • MySql
    • info
      • MySql 架构与历史
      • 02-key
  • kubernetes
    • 第二章 k8s 基本概念
    • 第一章 Kubernetes -- 伟大舵手
  • Redis
    • info
      • Redis 总览
      • 02-underline-ds
  • Shell&CInfo
    • GCC 与make的使用
    • C++ 中 malloc 与 new
    • 位运算符操作
    • Base of C macro
    • C 语言中 extern 关键字的用法
  • Distributed
    • info
      • 分布式理论概述
  • Java
    • info
      • Java 内存模型
  • Prometheus
    • Prometheus -- 不灭之火
Powered by GitBook
On this page
  • 1. Error usage
  • 1.1 获取错误类型与nil比较
  • 2. 获取错误更多信息的方法
  • 2.1 Assert a.(Type)从结构体的域中获取更多信息
  • 2.2 Assert a.(Type) 使用方法获取更多信息
  • 2.3 直接比较
  • 3. 自定义错误类型
  • 3.1 使用New()函数
  • 3.2 使用fmt.Errorf()函数替代
  • 3.3使用结构体类型和域获取错误的更多信息
  • 3.4 使用结构体的方法获取更多错误信息

Was this helpful?

  1. GoInfo
  2. Info

Go中的错误处理

[TOC]

1. Error usage

golang中错误的使用与其他语言中的类似。go中的错误类型使用的是内置的error类型。和其他内置类型一样,可以使用变量存储错误类型,作为函数或者方法的返回值。

可以使用多种方式进行错误的处理,对于可能的错误如果不加以处理,那么会造成不可预测的错误。可以有很多方法进行错误处理。

1.1 获取错误类型与nil比较

在go中error是一个接口类型,有着唯一的方法Error(),任何实现了该方法的类型都默认实现了该接口。也就有了错误处理机制。

type error interface {
    Error() string
}

该方法提供了一个类型的错误描述符。当打印一个error信息时,println函数调用该类型的错误描述符。

// use the type asserting to get more information
func open_error() {
  f, err := os.Open("tet")
  if err != nil{
      fmt.Printf("Err:%v, type:%T, path: %v\n", err, err)
      return
  }
  fmt.Println("Open succeccfully", f.Name())
}

上面代码试图打开一个文件,如果文件不存在会返回一个错误类型。可以使用err != nil,进行比较,观察是否产生错误。可以使用type asserting a.(Type),获取有关错误的更多信息。

关于文件打开错误的定义如下:

type PathError struct {
    Op string
    Path string
    Err error
}

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

2. 获取错误更多信息的方法

对于error这一接口类型,可以使用打印错误描述符获取其详细信息。对于以上例子的文件路径错误,如果需要获取文件的路径。通过打印描述符是一个糟糕的方法,因为错误描述符可能在新的版本中随时改变,代码也就无法继续生效。

可以通过很多方法获取错误的详细信息。

2.1 Assert a.(Type)从结构体的域中获取更多信息

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")
}

通过类型假设,对于错误类型有了更为精确的比较,返回的ok为bool类型。如果为真就可以确定该错误的具体类型,然后使用该类型中的属性的信息。

2.2 Assert a.(Type) 使用方法获取更多信息

通过比较某个错误类型是否属于一个具体的类型,然后调用该类型的方法获取更多信息。已知DNSError的定义如下:

type DNSError struct {  
    ...
}

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

有两个方法返回bool值,分别表示由于超时或者临时错误。

2.3 直接比较

第三种方法是使用一个error类型的变量直接进行比较。ErrBadPattern 定义在filepathpackage中:

var ErrBadPattern = errors.New("syntax error in pattern")

该错误产生于当filepath包中的Glob函数中传入的pattern不合法时。

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

3. 自定义错误类型

3.1 使用New()函数

创建并且使用自定义错误类型的方法是使用New()函数,可以使用error包中的New()函数,用以创建一个error类型的自定义错误类型。返回值是该错误的地址。

// package errors to implements functions to manipulate errors.
package errors

// return an error that formats as the given text.
func New(s string) error {
  return &errorString{s}
}

// errorString is a trivial implementation of error.
type errorString struct {
  s string
}

// implements the error interface, so the variable
// can be assigned to error type.
func (e *errorString) Error() string {
  return e.s
}

以上代码定义了一个存储string的错误类型(因为其指针类型实现了Error()方法,所以实现了error接口也就是错误类型,可以使用指针类型或者值类型调用Error,但是error类型变量只可以接收指针类型的errorString)。使用errors.New()方法可以返回一个*errorString类型的指针,使用指针类型可以避免不必要的参数复制。

具体关于该自定义错误类型的使用:

// use the errors.New get a errorString error
func circleArea(radius float64) (float64, error) {
  if radius < 0 {
    return 0, errors.New("The radius must not be be negative")
  }
  return math.Pi * radius * radius, nil
}

// use the fmt.Errorf to get same function
func rectanglArea(leng, wid float64) (float64, error) {
  if leng < 0 {
    return 0, fmt.Errorf("Given length of rectangle %v is not correct\n", leng)
  }
  if wid < 0 {
    return 0, fmt.Errorf("Given width of rectangle %v is not correct\n", wid)
  }
  return leng * wid, nil
}

3.2 使用fmt.Errorf()函数替代

可以使用fmt.Error()函数替代上述过程,直接得到更多的关于错误的格式化输出信息。

3.3使用结构体类型和域获取错误的更多信息

可以将错误信息作为一个结构体的域,然后使用结构体类型来实现error接口,快来作为errors类型。使用这种方式提供了更为灵活的错误处理机制。在上述例子中为了获取引起错误的radius,必须调用该错误的描述符。这不是处理错误的正确方法。

可以使用结构体的域对于错误进行访问。产生自定义类型的结构体,一般使用Error作为结尾

type areaError struct {
  err string
  radius float64
}

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

// use the errors.New get a errorString error
func circleArea(radius float64) (float64, error) {
  if radius < 0 {
    return 0, &areaError{"is nagative", radius}
  }
  return math.Pi * radius * radius, nil
}

func main() {
     radius := -20.
  var holder error
  area, err := circleArea(radius)
  if err != nil {
    holder = err     // 此处得到的err是一个指针类型,使用指针类型是为了避免不必要的参数复制
    fmt.Printf("%v, %T\n", holder, holder)
  } else {
    fmt.Println("Area of the circle:", area)
  }
}

/*radius -20.00: is nagative, *main.areaError*/

通过使用自定义错误类型,可以得到期待的所有结果。注意进行接口实现是一般针对指针类型进行实现,从而不需要进行多余的赋值操作。

注意对于检测一个错误类型是否为nil时,通常使用type asserting进行代替

3.4 使用结构体的方法获取更多错误信息

通过构建自定义错误类型,可以获取更多的错误信息。也可以定义该结构体的方法,返回一个bool值,然后在调用程序中进行进一步的操作。如下例:

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
}

func rectArea(length, width float64) (float64, error) {  
    err := ""
    if length < 0 {
        err += "length is less than zero"
    }
    if width < 0 {
        if err == "" {
            err = "width is less than zero"
        } else {
            err += ", width is less than zero"
        }
    }
    if err != "" {
        return 0, &areaError{err, length, width}
    }
    return length * width, nil
}

func main() {  
    length, width := -5.0, -9.0
    area, err := rectArea(length, width)
    if err != nil {
        if err, ok := err.(*areaError); ok {
            if err.lengthNegative() {
                fmt.Printf("error: length %0.2f is less than zero\n", err.length)

            }
            if err.widthNegative() {
                fmt.Printf("error: width %0.2f is less than zero\n", err.width)

            }
            return
        }
        fmt.Println(err)
        return
    }
    fmt.Println("area of rect", area)
}
PreviousPanic and RecoverNext并发

Last updated 5 years ago

Was this helpful?