Golang空接口之间的比较

时间:2019-01-02 08:28:25

标签: go interface comparison

根据specification:

  

接口值是可比较的。如果两个接口值相等   它们具有相同的动态类型和相等的动态值,或者   值为零。

var err error 
var reader io.Reader                           

据了解,errreader具有不同的动态类型(errorio.Reader),因此不可比。

fmt.Println(err == reader) 

将导致编译错误:

  

无效操作:err == reader(错误类型和io.Reader的不匹配)

如果为真,为什么Println命令对两个变量输出相同的结果?为什么两者都是nil

fmt.Printf("reader: %T", reader) // nil
fmt.Printf("error: %T", err) // nil

EDIT reflect.TypeOf(err)reflect.TypeOf(reader))也将输出nil。我不明白如果类型不同,为什么输出也一样。

1 个答案:

答案 0 :(得分:3)

的确,接口值是可比较的,但是您只能比较可分配给彼此的值(更准确地说,一个可分配给另一个)。引用自Spec: Comparison operators:

  

在任何比较中,第一个操作数必须为第二个操作数的类型的assignable,反之亦然。

您不能将error的值分配给io.Reader,也不能将io.Reader的值分配给error,所以您也不能比较它们。

如果您想比较它们,它们可能会或可能不会存储相同的动态值,请先将两者都隐瞒interface{},以便您可以对它们进行比较,例如:

fmt.Println(interface{}(err) == interface{}(reader))

这将输出(在Go Playground上尝试):

true

注意:实际上,仅将其中一个转换为interface{}就足够了,因为那样的话,另一个值将与您转换为interface{}的类型的值相当(任何值可以转换为interface{}),因此这样做也足够了:

fmt.Println(interface{}(err) == reader)

使用非nil接口值测试比较:

type x int

func (x) Error() string            { return "" }
func (x) Read([]byte) (int, error) { return 0, nil }

err = x(0)
reader = x(0)
fmt.Println(interface{}(err) == interface{}(reader))

reader = x(1)
fmt.Println(interface{}(err) == interface{}(reader))

现在将输出(在Go Playground上尝试):

true
false

也不要忘记nil接口值不等于保持nil动态值的非nil接口值。有关详细信息,请参见Hiding nil values, understanding why golang fails here

编辑:

fmt包在接口内部打印值,而不是接口值。引用fmt软件包的文档:

  

无论动词如何,如果操作数是接口值,则使用内部具体值,而不是接口本身。

reflect.TypeOf()相同:它返回动态类型,但是如果您向其传递一个nil接口值,它将返回nil,因此将打印fmtnil。引用其文档:

  

TypeOf返回表示i的动态类型的反射类型。如果i是一个nil接口值,则TypeOf返回nil。