Hello,
On Thu, Sep 01, 2016 at 01:59:12AM -0700, Muhammad Shulhan wrote:
> > type Slices []string
> >
> > func (sl *Slices) String() string {
> > return fmt.Sprint(sl)
> > }
> runtime: goroutine stack exceeds 250000000-byte limit
> fatal error: stack overflow
It is always dangerous to call fmt.Sprint() (or any other print method of
the fmt package) from a String() method of a value that implements the
Stringer interface. fmt.Sprint() might call the String() method itselfes,
which leads to infinite recursion.
From the fmt documentation (
https://golang.org/pkg/fmt/#pkg-overview):
| [...]
| 5. If an operand implements method String() string, that method will be
| invoked to convert the object to a string, which will then be formatted as
| required by the verb (if any).
Wether this happens or not depends on the concrete execution path of
fmt.Sprint(). Even if three of your four exampes work, I guess they could
fail with future implementations of the fmt package.
You should always pass basic types to fmt.Sprint(), e.g.
func (sl *Slices) String() string {
return fmt.Sprint([]string(*sl))
}
Again, from the fmt documentation:
| To avoid recursion in cases such as
|
| type X string
| func (x X) String() string { return Sprintf("<%s>", x) }
|
| convert the value before recurring:
|
| func (x X) String() string { return Sprintf("<%s>", string(x)) }
|
| Infinite recursion can also be triggered by self-referential data
| structures, such as a slice that contains itself as an element, if that type
| has a String method. Such pathologies are rare, however, and the package
| does not protect against them.
Harald