根据fortyforty对this question的回复:
fmt.Sprint(e)
会致电e.Error()
将值e
转换为astring
。如果Error()
方法调用fmt.Sprint(e)
,那么 程序递归直到内存不足。您可以通过将
e
转换为没有值的值来中断递归String
或Error
方法。
这对我来说仍然令人困惑。为什么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))
}
答案 0 :(得分:13)
似乎有人解释directly是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.
这意味着第一个error.Error()被调用来生成字符串,而不是再次处理它并打印成字符串。
error
方法String
是否与此无关。问题是为什么NegativeSqrt
用一种方法而不是另一种方法打印。类型NegativeSqrt
实现了fmt.Stringer
和error
接口,因此应该使用fmt
包的实现来使用哪个接口从{{1}获取string
()fmt.Sprint将参数设为NegativeSqrt
)。
为了说明这一点,请考虑以下示例:
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)
}
这是因为在Go类型中,开关的行为与普通开关一样,所以order of cases matters。
答案 1 :(得分:3)
因为类型为error
且error
的界面为
type error interface{
Error() string
}
每个error
必须使用Error() string
方法,但不必使用String() string
方法。这就是为什么首先检查Error()
方法的逻辑。
答案 2 :(得分:0)
让我扩大tumdum的发现,以便更清晰。
我会从通话电话跳到显示我们如何进入循环。
我们从练习开始
func (e NegativeSqrt) Error() string {
fmt.Printf(".")
return fmt.Sprint(e)
}
它将我们带到fmt/print.go的第237行:
func Sprint(a ...interface{}) string
在函数内部,我们的下一个跳转是在第239行:
p.doPrint(a, false, false)
我们到达第1261行:
func (p *pp) doPrint(a []interface{}, addspace, addnewline bool) {
在该函数中,我们将使用error
参数通过第1273行跳转:
prevString = p.printArg(arg, 'v', 0)
我们在第738行找到了一个巨大的核心怪物功能:
func (p *pp) printArg(arg interface{}, verb rune, depth int) (wasString bool) {
在其中,你可以看到一个很大的switch case
开关。 error
位于default
部分,因为它被视为非平凡类型。
通过调用handleMethods()
if handled := p.handleMethods(verb, depth); handled {
我们到达第688行:
func (p *pp) handleMethods(verb rune, depth int) (handled bool) {
在该函数内部,在第724行,调用Error()
,这完成了循环:
p.printArg(v.Error(), verb, depth)