困惑:在Go中实现多个接口

In the below code the type ErrNegativeSqrt implements both Stringer and error interfaces. Since in Sqrt method the return type is fmt.Stringer, I would except the execution result to be:

0 nil

0 Impl Stringer type

But the actual result is the following, why?

0 nil

0 Impl error type

package main

import (
    "fmt"
)

type ErrNegativeSqrt float64

func Sqrt(x ErrNegativeSqrt) (float64, fmt.Stringer) {
    if x < 0 {
        return 0, ErrNegativeSqrt(x)
    }
    return 0, nil
}

func (e ErrNegativeSqrt) String() string {
    return "Impl Stringer type"
}

func (e ErrNegativeSqrt) Error() string {
    return "Impl error type"
}

func main() {
    fmt.Println(Sqrt(2))
    fmt.Println(Sqrt(-2))
}

The documentation for Package fmt states that:

... special formatting considerations apply for operands that implement certain interfaces. In order of application:

...

  1. If the %v verb is used with the # flag (%#v) and the operand implements the GoStringer interface, that will be invoked.

If the format (which is implicitly %v for Println etc.) is valid for a string (%s %q %v %x %X), the following two rules apply:

  1. If an operand implements the error interface, the Error method will be invoked ...

  2. If an operand implements method String() string, that method will be invoked ...

Since you are using fmt.Println, rules 4 and 5 come into play, which prefers to call Error() over String()

You're ignoring the fact that your function returns a fmt.Stringer by passing the resulting value to fmt.Println as an interface{}.

You see the result from the Error() method only because the fmt package checks for the error interface before it checks for the fmt.Stringer interface.