package main
import "fmt"
type TT struct {
a int
b float32
c string
}
func (t *TT) String() string {
return fmt.Sprintf("%+v", *t)
}
func main() {
tt := &TT{3, 4, "5"}
fmt.Printf(tt.String())
}
The code can work well. But if I change the String
method as in the following, it will cause dead loop. The difference is that the *t
is replaced with t
. Why?
func (t *TT) String() string {
return fmt.Sprintf("%+v", t)
}
Because the
fmt
package checks if the value being printed has aString() string
method (or in other words: if it implements thefmt.Stringer
interface), and if so, it will be called to get thestring
representation of the value.This is documented in the
fmt
package doc:Here:
You are passing a value
*t
of typeTT
to thefmt
package. If theTT.String()
method has a pointer receiver, then the method set of the typeTT
does not include theString()
method, so thefmt
package will not call it (only the method set of*TT
includes it).If you change the receiver to non-pointer type, then the method set of the type
TT
will include theString()
method, so thefmt
package will call that, but this is the method we're currently in, so that's an endless "indirect recursion".Prevention / protection
If for some reason you do need to use the same receiver type as the type of the value you pass to the
fmt
package, an easy and common way to avoid this / protect from it is to create a new type with thetype
keyword, and use type conversion on the value being passed:Try this on the Go Playground.
But why does this work? Because the
type
keyword creates a new type, and the new type will have zero methods (it does not "inherit" the methods of the underlying type).Does this incur some run-time overhead? No. Quoting from Spec: Type declarations:
Read more about this here: Does convertion between alias types in Go create copies?