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

-- 
You received this message because you are subscribed to the Google Groups 
"golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to golang-nuts+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to