错误,无限循环

pyr*_*hic 28 go

我正在阅读Go语言教程.

我想查看这个问题的答案:

注意:fmt.Sprint(e)Error方法内部的调用会将程序发送到无限循环.您可以通过e先转换来避免这种情况:fmt.Sprint(float64(e)).为什么?

我相信这是因为当Sprint调用函数时,由于错误是非零的,所以Error function()将再次调用,依此类推,从而导致无限循环.

小智 47

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

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

  • 是的, `fmt.Sprintf("cannot Sqrt negative number: %f", e)` 有效 (3认同)
  • @hytromo 在 [fmt/print.go](https://golang.org/src/fmt/print.go?s=7053:7089) 中,“Sprint”最终导致“handleMethods”,动词为“v” 。[handleMethods 中的开关](https://golang.org/src/fmt/print.go#L614) 检查参数是否满足 Stringer 之前的错误类型,从而导致调用 `Error()` 方法而不是 `字符串()`。 (3认同)
  • 将 e 转换为可能具有不会无限递归的 String/Error 方法的类型还不够吗? (2认同)
  • 但为什么它会尝试调用“e.Error()”来进行转换呢?如果我尝试让它实现 Stringer 接口,它不会尝试调用它。是什么让它寻找 `Error()` 方法? (2认同)

小智 17

fmt.Sprint(e) 将调用“fmt/print.go”中的以下代码

switch verb {
    case 'v', 's', 'x', 'X', 'q':
        // Is it an error or Stringer?
        // The duplication in the bodies is necessary:
        // setting handled and deferring catchPanic
        // must happen before calling the method.
        switch v := p.arg.(type) {
        case error:
            handled = true
            defer p.catchPanic(p.arg, verb, "Error")
            p.fmtString(v.Error(), verb)
            return

        case Stringer:
            handled = true
            defer p.catchPanic(p.arg, verb, "String")
            p.fmtString(v.String(), verb)
            return
        }
    }
Run Code Online (Sandbox Code Playgroud)

当错误情况首先出现时,v.Error()将被执行。这里无限循环!