由Error方法中的fmt.Sprint(e)生成的无限循环

Dav*_*rri 12 go

根据fortyforty对这个问题的回复:

fmt.Sprint(e)将调用e.Error()将值转换e为a string.如果Error()方法调用fmt.Sprint(e),则程序会递归直到内存不足.

您可以通过将e值转换为不带StringError方法的值 来中断递归.

这对我来说仍然令人困惑.为什么fmt.Sprint(e)调用e.Error()而不是String()?我尝试使用Stringer接口,这是我的代码:

package main

import (
  "fmt"
  "math"
)

type NegativeSqrt float64

func (e NegativeSqrt) Error() string {
  fmt.Printf(".")
  return fmt.Sprint(e)
}

func (e NegativeSqrt) String() string {
  return fmt.Sprintf("%f", e)
}

func Sqrt(x float64) (float64, error) {
  if x < 0 {
    return 0, NegativeSqrt(x)
  }
  return math.Sqrt(x), nil
}

func main() {
  fmt.Println(Sqrt(2))
  fmt.Println(Sqrt(-2))
}
Run Code Online (Sandbox Code Playgroud)

tum*_*dum 14

它似乎直接解释了fmt包的来源:

// Is it an error or Stringer?
// The duplication in the bodies is necessary:
// setting handled and deferring catchPanic
// must happen before calling the method.
Run Code Online (Sandbox Code Playgroud)

并且比调用Error()String().

这意味着首先调用error.Error()来生成字符串,该字符串再次处理并打印为字符串.

是否error有方法String在这里无关紧要.问题是为什么NegativeSqrt用一种方法而不是另一种方法打印.类型NegativeSqrt同时实现了fmt.Stringererror接口,所以它是由执行fmt封装的接口应该被用来获取string来自NegativeSqrt(因为fmt.Sprint通过采用其参数interface{}).

为了说明这个,请考虑以下示例

package main

import (
    "fmt"
)

type NegativeSqrt float64

func (e NegativeSqrt) Error() string {
    return ""
}

func (e NegativeSqrt) String() string {
    return ""
}

func check(val interface{}) {
    switch val.(type) {
    case fmt.Stringer:
        fmt.Println("It's stringer")
    case error:
        fmt.Println("It's error")
    }
}

func check2(val interface{}) {
    switch val.(type) {
    case error:
        fmt.Println("It's error")
    case fmt.Stringer:
        fmt.Println("It's stringer")
    }
}

func main() {
    var v NegativeSqrt
    check(v)
    check2(v)
}
Run Code Online (Sandbox Code Playgroud)

执行此操作会给出:

% go run a.go
It's stringer
It's error
Run Code Online (Sandbox Code Playgroud)

这是因为在Go类型中,开关的行为与普通开关一样,因此情况顺序很重要.


fab*_*ioM 5

因为类型是error,接口error

  type error interface{
     Error() string
  }
Run Code Online (Sandbox Code Playgroud)

每个人都error必须有一个Error() string方法,但不一定要有一个String() string方法。这就是为什么首先检查Error()方法的逻辑。