go自定义的错误返回nil != nil 的问题
func returnsError() error {
	var p *MyError = nil
	if bad() {
		p = ErrBad
	}
	return p // Will always return a non-nil error.
}

上面返回的  p  永远不会与 nil 相等。

这是为什么呢,因为 error 是一个 interface,从类型比较可以知道,interface 之间比较需要保证两者的 Type 和 Value 两两相等:

  • 语言内的  nil  可以理解为一个 Type 和 Value 均为空的 interface
  • 代码里面返回的 p 虽然 Value 为空,但是 Type 是 *MyError

所以 p!=nil 。

正确的代码应该是这样的:

func returnsError() error {
	if bad() {
		return ErrBad
	}
	return nil
}

这个问题不仅仅是抛出错误的时候会出现,任何返回 interface 的场景都需要注意。

Go 类型可比较与可排序约定

TypeComparableOrderedDescription
Boolean✅❌
Integer✅✅
Float✅✅
Complex✅❌分别比较实数和虚数,同时相等则两个复数相等。 如果需要比较大小,需要开发者分别比较实数和虚数。
String✅✅基于字节逐个比较。
Pointer✅❌如果两个指针指向同一个对象或者都为 nil,则两者相等。
Channel✅❌类似 Pointer,两个 Channel 变量只有都为 nil,或者指向同一个 Channel 的时候才相等。
Interface✅❌两个 interface 的 Type 和 Value 值同时相等时,两者才相等。
Struct⚠️❌仅当 Struct 内所有成员都是 Comparable,这个 Struct 才是 Comparable 的。 如果两个 struct 类型相同,且所有非空成员变量都相等,则两者相等。
Array⚠️❌仅当成员为 Comparable,Array 才是 Comparable 的。 如果两个 Array 中的每一个元素一一相等时,则两个 Array 相等。
Map❌❌
Slice❌❌
Func❌❌

参考 : 深入理解 Go Comparable Type Go FAQ