ZetCode

Golang fmt.GoStringer Interface

last modified May 8, 2025

This tutorial explains how to use the fmt.GoStringer interface in Go. We'll cover interface basics with practical examples of custom Go syntax output.

The GoStringer interface is used to customize the Go syntax representation of values. It's similar to Stringer but used with the %#v format verb.

In Go, GoStringer is implemented by types that want to control their representation when printed with %#v. This is useful for debugging and testing.

Basic GoStringer implementation

The simplest use of GoStringer provides custom Go syntax output. This example demonstrates basic interface implementation.
Note: The %#v verb triggers GoString() method calls.

basic_gostringer.go
package main

import "fmt"

type Point struct {
    X, Y int
}

func (p Point) GoString() string {
    return fmt.Sprintf("Point{X: %d, Y: %d}", p.X, p.Y)
}

func main() {
    p := Point{X: 10, Y: 20}
    fmt.Printf("Regular: %v\n", p)
    fmt.Printf("Go syntax: %#v\n", p)
}

The Point type implements GoStringer to provide custom Go syntax output. %v shows default format while %#v uses our GoString() method.

GoStringer with private fields

GoStringer can expose private fields in a controlled way. This example shows how to represent structs with unexported fields using GoString().

private_fields.go
package main

import "fmt"

type secretData struct {
    public  string
    private string
}

func (s secretData) GoString() string {
    return fmt.Sprintf("secretData{public: %q, private: \"****\"}", s.public)
}

func main() {
    data := secretData{
        public:  "visible",
        private: "hidden",
    }
    fmt.Printf("%#v\n", data)
}

The GoString() method hides the private field while showing the public one. This maintains encapsulation while providing debug information.

GoStringer for custom collections

Implementing GoStringer for collection types improves debugging output. This example shows a custom list type with GoString() implementation.

custom_collection.go
package main

import (
    "fmt"
    "strings"
)

type StringList []string

func (sl StringList) GoString() string {
    var builder strings.Builder
    builder.WriteString("StringList{")
    for i, s := range sl {
        if i > 0 {
            builder.WriteString(", ")
        }
        builder.WriteString(fmt.Sprintf("%q", s))
    }
    builder.WriteString("}")
    return builder.String()
}

func main() {
    list := StringList{"apple", "banana", "cherry"}
    fmt.Printf("%#v\n", list)
}

The StringList type implements GoStringer to show its contents clearly. The output matches valid Go syntax for initializing the collection.

GoStringer with pointer receivers

GoStringer can be implemented with pointer receivers for mutable types. This example demonstrates pointer receiver implementation.

pointer_receiver.go
package main

import "fmt"

type Counter struct {
    value int
}

func (c *Counter) Increment() {
    c.value++
}

func (c *Counter) GoString() string {
    return fmt.Sprintf("&Counter{value: %d}", c.value)
}

func main() {
    c := &Counter{value: 5}
    fmt.Printf("%#v\n", c)
    c.Increment()
    fmt.Printf("%#v\n", c)
}

The Counter type uses a pointer receiver for GoString() to match its methods. This maintains consistency in the type's representation.

GoStringer for interface values

GoStringer implementations can help debug interface values. This example shows how to implement GoStringer for interface types.

interface_values.go
package main

import "fmt"

type Shape interface {
    Area() float64
    GoString() string
}

type Circle struct {
    Radius float64
}

func (c Circle) Area() float64 {
    return 3.14 * c.Radius * c.Radius
}

func (c Circle) GoString() string {
    return fmt.Sprintf("Circle{Radius: %g}", c.Radius)
}

func printShape(s Shape) {
    fmt.Printf("%#v\n", s)
}

func main() {
    c := Circle{Radius: 5.0}
    printShape(c)
}

The Shape interface includes GoStringer, ensuring all implementations provide debug output. This helps when working with interface values.

Combining Stringer and GoStringer

Types can implement both Stringer and GoStringer for different outputs. This example shows a type with both interfaces implemented.

combined_interfaces.go
package main

import "fmt"

type Person struct {
    Name string
    Age  int
}

func (p Person) String() string {
    return fmt.Sprintf("%s (%d years)", p.Name, p.Age)
}

func (p Person) GoString() string {
    return fmt.Sprintf("Person{Name: %q, Age: %d}", p.Name, p.Age)
}

func main() {
    p := Person{Name: "Alice", Age: 30}
    fmt.Println(p)       // Uses String()
    fmt.Printf("%v\n", p) // Uses String()
    fmt.Printf("%#v\n", p) // Uses GoString()
}

The Person type provides different outputs for %v and %#v format verbs. String() is for human-readable output, GoString() for Go syntax.

GoStringer with nested structs

GoStringer implementations can handle nested structs recursively. This example demonstrates GoString() for a complex structure.

nested_structs.go
package main

import "fmt"

type Address struct {
    Street  string
    City    string
    Country string
}

func (a Address) GoString() string {
    return fmt.Sprintf("Address{Street: %q, City: %q, Country: %q}",
        a.Street, a.City, a.Country)
}

type User struct {
    Name    string
    Age     int
    Address Address
}

func (u User) GoString() string {
    return fmt.Sprintf("User{Name: %q, Age: %d, Address: %#v}",
        u.Name, u.Age, u.Address)
}

func main() {
    user := User{
        Name: "Bob",
        Age: 40,
        Address: Address{
            Street:  "123 Main St",
            City:    "Springfield",
            Country: "USA",
        },
    }
    fmt.Printf("%#v\n", user)
}

Both User and Address implement GoStringer for complete representation. The nested Address is properly formatted using %#v recursively.

Source

Go package documentation

This tutorial covered the fmt.GoStringer interface in Go with practical examples of custom Go syntax representation for various types.

Author

My name is Jan Bodnar, and I am a passionate programmer with extensive programming experience. I have been writing programming articles since 2007. To date, I have authored over 1,400 articles and 8 e-books. I possess more than ten years of experience in teaching programming.

List all Golang tutorials.