Comparison between empty interfaces in Golang

无人久伴 提交于 2021-01-29 07:33:23

问题


According to the specification:

Interface values are comparable. Two interface values are equal if they have identical dynamic types and equal dynamic values or if both have value nil.

var err error 
var reader io.Reader                           

As far as understand, err and reader have different dynamic types (error and io.Reader) and therefore are not comparable.

fmt.Println(err == reader) 

will cause a compile error:

invalid operation: err == reader (mismatched types error and io.Reader)

If it is true, why Println command outputs the same results for both variables? Why both are nil?

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

EDIT reflect.TypeOf(err)or reflect.TypeOf(reader) will also output nil. I do not understand why the output is the same if the types are different.


回答1:


It's true that interface values are comparable, but you can only compare values that are assignable to each other (more precisely, one is assignable to the other). Quoting from Spec: Comparison operators:

In any comparison, the first operand must be assignable to the type of the second operand, or vice versa.

You can't assign an error value to an io.Reader, and you can't assign an io.Reader value to an error either, so you can't compare them.

They may or may not store the same dynamic value, if you want to compare those, first covert both to interface{}, so you can compare them, e.g.:

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

This will output (try it on the Go Playground):

true

Note: actually it would be enough to convert only one of them to interface{}, because that way the the other value will become comparable to the type of the one you converted to interface{} (any value is convertible to interface{}), so it would also be enough to do:

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

Testing the comparison with non-nil interface values:

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

Now output will be (try it on the Go Playground):

true
false

Also don't forget that a nil interface value does not equal to a non-nil interface value holding a nil dynamic value. For details, see Hiding nil values, understanding why golang fails here

Edit:

The fmt package prints the value inside the interface, not the interface value. Quoting from package doc of fmt:

Regardless of the verb, if an operand is an interface value, the internal concrete value is used, not the interface itself.

Same goes with reflect.TypeOf(): it returns the dynamic type, but if you pass a nil interface value to it, it returns nil so the fmt package will print nil. Quoting its doc:

TypeOf returns the reflection Type that represents the dynamic type of i. If i is a nil interface value, TypeOf returns nil.



来源:https://stackoverflow.com/questions/54003271/comparison-between-empty-interfaces-in-golang

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!