Error方法中由fmt.Sprint(e)产生的无限循环 [英] An infinite loop produced by fmt.Sprint(e) inside the Error method
问题描述
根据fortyforty对这个问题的回复:
fmt.Sprint(e)
会调用e.Error()
将值e
转换为
字符串
。如果Error()
方法调用fmt.Sprint(e)
,那么
程序会递归直到out的内存。
您可以通过将
e
转换为一个没有
String
或Error
方法。
这仍然让我感到困惑。为什么fmt.Sprint(e)调用e.Error()而不是String()?我尝试使用Stringer接口,这是我的代码:
package main
import(
fmt
math
)
类型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))
}
看来这是解释直接是fmt包的来源:
/ /这是一个错误还是斯金格?
//体内的重复是必需的:
//设置处理并且延迟catchPanic
// //在调用方法之前必须发生。
这意味着首先 error.Error()被调用来产生字符串,该字符串被再次处理并被打印为字符串。
error 方法 String
在这里是不相关的。问题是为什么 NegativeSqrt
是用一种方法打印的,而不是另一种。键入 NegativeSqrt
实现 fmt.Stringer
和错误
接口它取决于 fmt
包的实现,应该使用哪个接口从中获取
(自 fmt.Sprint 的参数是由 string
NegativeSqrt interface {}
)。
包裹主要
进口(
fmt
)
类型NegativeSqrt float64
func(e NegativeSqrt)Error()字符串{
返回
}
func(e NegativeSqrt)字符串()string {
return
}
func check(val interface {}){
switch val。(type){
case fmt .Stringer:
fmt.Println(It's stringer)
大小写错误:
fmt.Println(这是错误)
}
}
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 run a.go
它是一条龙
它错误
这是因为在Go类型开关中的行为与普通开关类似,所以案件顺序问题。
According to fortyforty's reply to this question:
fmt.Sprint(e)
will calle.Error()
to convert the valuee
to astring
. If theError()
method callsfmt.Sprint(e)
, then the program recurses until out of memory.You can break the recursion by converting the
e
to a value without aString
orError
method.
This is still confusing to me. Why does fmt.Sprint(e) call e.Error() instead of String()? I tried using the Stringer interface, this is my code:
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))
}
It seems it's explained directly is source of fmt package:
// Is it an error or Stringer?
// The duplication in the bodies is necessary:
// setting handled and deferring catchPanic
// must happen before calling the method.
And than Error() or String() is called.
What it means is that first error.Error() is called to produce string, which is than once again processed and is printed as string.
Whether error
has method String
is irrelevant here. The question is why NegativeSqrt
is printed with one method and not the other. Type NegativeSqrt
implements both fmt.Stringer
and error
interfaces so it's up to the implementation of fmt
package which of interfaces should be used to get string
from NegativeSqrt
(since fmt.Sprint takes its parameters by interface{}
).
To illustrate this consider this example:
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)
}
Executing this gives:
% go run a.go
It's stringer
It's error
This is because in Go type switch behaves just like normal switch, so order of cases matters.
这篇关于Error方法中由fmt.Sprint(e)产生的无限循环的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!