Menu
Coddy logo textTech

fmt.Stringer Interface

Part of the Object Oriented Programming section of Coddy's GO journey — lesson 75 of 107.

The fmt.Stringer interface controls how your types appear when printed. It's one of the most commonly implemented interfaces in Go, defined in the fmt package:

type Stringer interface {
    String() string
}

When you pass a value to fmt.Println, fmt.Printf with %v, or similar functions, Go checks if the type implements Stringer. If it does, Go calls the String() method to get the text representation.

type Temperature struct {
    Celsius float64
}

func (t Temperature) String() string {
    return fmt.Sprintf("%.1f°C", t.Celsius)
}

func main() {
    temp := Temperature{Celsius: 23.5}
    fmt.Println(temp)  // 23.5°C
}

Without the String() method, printing would show the default struct format: {23.5}. By implementing Stringer, you control exactly how your type presents itself.

This is particularly useful for types where the raw field values don't convey meaning clearly. A Duration type might display as "2h 30m" instead of showing raw nanoseconds, or a User type might show a formatted name instead of all its fields.

challenge icon

Challenge

Easy

Let's build a time tracking system that displays durations in a human-friendly format! You'll implement the fmt.Stringer interface to control how your custom types appear when printed.

You'll organize your code across two files:

  • duration.go: Define your time-related types with custom string representations.

    Create a Duration struct that stores a total number of minutes as an integer. Implement the String() method so that when printed, it displays in a readable format like 2h 30m for 150 minutes, or 0h 45m for 45 minutes. Hours and minutes should always be shown.

    Create a Task struct with fields for Name (string) and Time (Duration). Implement String() on Task to display in the format [Name]: [duration], where the duration uses its own String method.

  • main.go: Build and display tasks with their durations.

    Read a count of tasks, then for each task read its name and duration in minutes. Create Task instances and print each one directly using fmt.Println—the Stringer interface will handle the formatting automatically.

    After printing all tasks, calculate and print the total time across all tasks in the format:

    Total: [duration]

The following inputs will be provided:

  • Line 1: Number of tasks
  • Following lines: Task name and minutes (two lines per task)

For example, given:

3
Code Review
90
Meeting
45
Documentation
120

Your output should be:

Code Review: 1h 30m
Meeting: 0h 45m
Documentation: 2h 0m
Total: 4h 15m

And given:

2
Design
180
Testing
65

Your output should be:

Design: 3h 0m
Testing: 1h 5m
Total: 4h 5m

By implementing Stringer, your types integrate seamlessly with Go's printing functions. Instead of seeing raw struct fields like {90}, you get meaningful output that makes sense to users.

Cheat sheet

The fmt.Stringer interface controls how types appear when printed:

type Stringer interface {
    String() string
}

When you pass a value to fmt.Println or fmt.Printf with %v, Go checks if the type implements Stringer. If it does, Go calls the String() method to get the text representation.

Example implementation:

type Temperature struct {
    Celsius float64
}

func (t Temperature) String() string {
    return fmt.Sprintf("%.1f°C", t.Celsius)
}

func main() {
    temp := Temperature{Celsius: 23.5}
    fmt.Println(temp)  // 23.5°C
}

Without the String() method, printing shows the default struct format: {23.5}. By implementing Stringer, you control exactly how your type presents itself, making output more meaningful and user-friendly.

Try it yourself

package main

import (
	"bufio"
	"fmt"
	"os"
	"strconv"
	"strings"
)

func main() {
	reader := bufio.NewReader(os.Stdin)

	// Read number of tasks
	line, _ := reader.ReadString('\n')
	numTasks, _ := strconv.Atoi(strings.TrimSpace(line))

	// TODO: Create a slice to store tasks
	// TODO: Track total minutes

	for i := 0; i < numTasks; i++ {
		// Read task name
		name, _ := reader.ReadString('\n')
		name = strings.TrimSpace(name)

		// Read task duration in minutes
		minutesLine, _ := reader.ReadString('\n')
		minutes, _ := strconv.Atoi(strings.TrimSpace(minutesLine))

		// TODO: Create a Task with the name and Duration
		// TODO: Print the task (fmt.Println will use the Stringer interface)
		// TODO: Add minutes to total
		_ = name
		_ = minutes
	}

	// TODO: Print the total duration in format "Total: Xh Ym"
}
quiz iconTest yourself

This lesson includes a short quiz. Start the lesson to answer it and track your progress.

All lessons in Object Oriented Programming