问题
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