IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    golang error和nil详解

    mckee发表于 2015-11-08 00:23:16
    love 0

    go处理错误的方式非常原始和有效,go是通过function返回error类型而非主流语言抛出异常。在golang里永远不要忽略错误,否则可能导致程序的意外崩溃。
    通常用如下方式检测错误:

    if value, err := pack1.Func1(param1); err != nil {
        fmt.Printf(“Error %s in pack1.Func1 with parameter %v”, err.Error(), param1)
        return    // or: return err
    }
    // Process(value)

    从上可以看出如果err不为nil表明存在错误。那么error和nil是啥?
    error是golang的预定义接口:
    type error interface {
    	Error() string
    }

    那么如何定义error?
    package main
    
    import (
    	"fmt"
    	"errors"
    )
    
    type myError struct{}
    
    func (this *myError) Error() string { return "" }
    
    func main()  {
    	//方法一:采用errors包的New方法 返回一个err的类型
    	var err1 error = errors.New("this is an error")
    	fmt.Println(err1.Error())
    
    	//方法二:采用fmt.Errof 将string信息转化为error信息 并返回
    	err2 := fmt.Errorf("%s", "the error test for fmt.Errorf")
    	fmt.Println(err2.Error())
    
    	//方法三:自定义error,下面细说
    }

    我们已经知道golang的error是一个interface,go中interface是作为两个成员实现:一个类型和一个值。该值被称为接口的动态值, 它是一个任意的具体值,而该接口的类型则为该值的类型。对于 int 值3, 一个接口值示意性地包含(int, 3)。
    只有在内部值和类型都未设置时(nil, nil),一个接口的值才为 nil。特别是,一个 nil 接口将总是拥有一个 nil 类型。若我们在一个接口值中存储一个 int 类型的指针,则内部类型将为 int,无论该指针的值是什么,这样的接口值会是非 nil 的,即使在该指针的内部值为 nil,形如(*int, nil)。
    下面举个简单的例子:
    package main
    
    import (
    	"math"
    	"fmt"
    	"reflect"
    )
    
    // 定义接口 Abser
    type Abser interface {
    	Abs() float64
    }
    
    // 定义结构体 Vertex
    type Vertex struct {
    	X, Y float64
    }
    
    // 实现方法 Abs
    func (v *Vertex) Abs() float64 {
    	return math.Sqrt(v.X*v.X + v.Y*v.Y)
    }
    
    func main() {
    	v := Vertex{3, 4}
    	// 成功,能够持有 *Vertex 类型的值
    	var a Abser = &v
    
    	fmt.Println(reflect.TypeOf(v)) //main.Vertex
    	fmt.Println(reflect.TypeOf(a)) //*main.Vertex
    
    	// 出错,不能持有 Vertex 类型的值
    	// 因为在 *Vertex 上定义了方法 Abs,而未在 Vertex 上定义
    	//var b Abser = v
    }

    那么go在自定义error的时候就要注意了:
    package main
    
    import (
    	"errors"
    	"fmt"
    	"reflect"
    )
    
    type myError struct{}
    
    func (this *myError) Error() string { return "" }
    
    func bad() bool {
    	return true
    }
    
    //自定义错误返回函数
    func test() error {
    	var p *myError = nil
    	if bad() {
    		return p
    	}
    	return nil
    }
    
    //只是返回错误非空
    func test1() error {
    	var val error = errors.New("val")
    	return val
    
    }
    
    func main() {
    	var e error = test()
    	if e == nil {
    		fmt.Println("e is nil")
    	} else {
    		fmt.Println(reflect.TypeOf(e))
    		fmt.Println(reflect.ValueOf(e))
    		fmt.Println("e is not nil")
    	}
    
    	var e1 error = test1()
    	if e1 == nil {
    		fmt.Println("e1 is nil")
    	} else {
    		fmt.Println("e1 is not nil")
    		fmt.Println(e1.Error())
    	}
    
    	/*输出如下:
    	*main.myError
    	<nil>
    	e is not nil
    	e1 is not nil
    	val
    	 */
    }

    再来说说nil:
    golang的nil在概念上和其它语言的null、None、nil、NULL一样,都指代零值或空值。nil是预先说明的标识符,也即通常意义上的关键字。在golang中,nil只能赋值给指针、channel、func、interface、map或slice类型的变量。如果未遵循这个规则,则会引发panic。



沪ICP备19023445号-2号
友情链接