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。