← Back to Go Course | Chapter 7: Interfaces | Lesson 5 of 7

The Stringer Interface

Implementing the Stringer interface is like teaching your custom type how to introduce itself politely whenever someone prints it, instead of showing a confusing default.

Implementing Stringer

The standard library's fmt.Stringer interface requires exactly one method, String() string. Any type that implements it gets used automatically whenever it's printed with Println, Printf's %v, or similar.

Example: Implementing Stringer

markup
package main

import "fmt"

type Point struct {
	X, Y int
}

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

func main() {
	p := Point{3, 4}
	fmt.Println(p)
}

Without vs With Stringer

A struct without a String() method prints its default, somewhat verbose field-by-field representation, while implementing Stringer gives you full control over exactly how it reads when printed.

Example: Without vs With Stringer

markup
package main

import "fmt"

type Status int

const (
	Active Status = iota
	Inactive
)

func (s Status) String() string {
	if s == Active {
		return "Active"
	}
	return "Inactive"
}

func main() {
	fmt.Println(Active)
	fmt.Println(Inactive)
}

Avoiding Infinite Recursion

A common mistake is calling fmt.Sprintf("%v", p) on the receiver p inside its own String() method -- since %v triggers String() again, this recurses forever. Building the string from individual fields avoids the problem.

Note: Always build the String() output from the struct's individual fields, never the receiver as a whole.

Example: Avoiding Infinite Recursion

markup
package main

import "fmt"

type Temp struct {
	Celsius float64
}

func (t Temp) String() string {
	return fmt.Sprintf("%.1f°C", t.Celsius) // uses the field, not t itself
}

func main() {
	fmt.Println(Temp{Celsius: 21.5})
}
Common Mistakes
  1. Naming the method something other than exactly 'String() string' -- fmt only recognizes that exact signature for the Stringer interface.
  2. Accidentally causing infinite recursion by calling fmt.Sprintf("%v", t) on the receiver itself inside its own String() method.
  3. Forgetting that a String() method defined with a pointer receiver only applies when printing a pointer to the type, not the value itself.
Chapter Summary
  • The fmt.Stringer interface requires one method: String() string.
  • Implementing it lets fmt.Println and %v automatically use your custom, readable representation.
  • Calling fmt formatting functions on the receiver itself inside String() causes infinite recursion -- format the underlying fields instead.
  • Stringer is a great example of Go's small, implicit interfaces in everyday use.
🔒

Chapter Quiz — Complete all 7 topics to unlock

0/7 topics done

Complete these topics first:

Login to run this code

C/C++/Java/PHP execution requires a free account. Your code is saved — you'll land right back in the editor after logging in.