Skip to content

Exercise 9 of 10 · Structs and methods

Playlist Runtime

What you will make

A playlist printout showing each song's length as minutes:seconds, plus the total runtime of the whole playlist.

The one new idea: Defining a struct with fields and a method on it (func (s Song) Format() string), used across a slice of structs

Structs with methods are how Go groups related data with the logic that acts on it, which is the shape most real Go code takes once programs grow past a handful of loose variables.

Go straight to the code ↓

A type Song struct { Title string; Seconds int } groups related data into one value, and func (s Song) Format() string attaches behavior to it — inside the method, s refers to whichever Song value it was called on, so song.Format() runs the method with s bound to song. Splitting a duration into minutes and seconds is a classic use of two operators together: / gives you the whole minutes, and % (modulo) gives you whatever's left over that doesn't make a full minute.

Worked example

Here's the same Song struct and method used on a two-song playlist:

Go
package main

import "fmt"

type Song struct {
	Title   string
	Seconds int
}

func (s Song) Format() string {
	minutes := s.Seconds / 60
	seconds := s.Seconds % 60
	return fmt.Sprintf("%d:%02d", minutes, seconds)
}

func main() {
	playlist := []Song{
		{"Rainy Day", 125},
		{"Night Drive", 305},
	}

	totalSeconds := 0
	fmt.Println("Playlist:")
	for i := 0; i < len(playlist); i++ {
		song := playlist[i]
		fmt.Printf("%s - %s\n", song.Title, song.Format())
		totalSeconds = totalSeconds + song.Seconds
	}

	fmt.Printf("Total runtime: %d:%02d\n", totalSeconds/60, totalSeconds%60)
}
Output
Playlist:
Rainy Day - 2:05
Night Drive - 5:05
Total runtime: 7:10

Each song's Format() call turns its raw second count into a clean minutes:seconds string, and the loop keeps a running total across all of them.

Your turn

The starter program's Format method computes minutes correctly but reuses the wrong operator for seconds, and the loop in main is meant to build up a running total but shrinks it instead. Fix both marked lines.

If something goes wrong

If every song's seconds display matches its minutes (like "3:3" instead of "3:35"), you're still dividing twice instead of using % for the second value. If the total runtime prints as a negative-looking or oddly small time, check that the accumulator line adds each song's seconds rather than subtracting them. With this playlist's three songs (215, 187, and 260 seconds), the total is 662 seconds — 11 whole minutes and 2 leftover seconds — so a total that doesn't match that means one of the two fixes is still missing.

Write your code

Runs in your browser. Press Run (or Ctrl/Cmd+Enter) and the output is checked for you.

Ctrl/Cmd+Enter to run

Press Esc then Tab to move keyboard focus out of the code editor.

Ready
Output will appear here after you run your code.

The runtime is starting in the background. You can type now — it will be ready before you are.

The answer appears here once you have run your code at least once.

Things that often go wrong here

Using / twice when one calculation needs the remainder instead.
% (modulo) gives you what's left over after dividing, which is exactly what's needed for the seconds portion of a minutes:seconds display — / alone only gives whole minutes.
Subtracting inside an accumulator loop instead of adding.
A running total that's supposed to build up across a loop needs +=, or the equivalent total = total + x — using - drains the total instead of growing it.
Defining a method with a name that doesn't match how it's called.
func (s Song) Format() string must be called as song.Format() on a Song value; mismatching the receiver type or method name is a compile error.
Forgetting %02d pads single-digit numbers with a leading zero.
Without the 0 flag, 5 seconds would print as "3:5" instead of the conventional "3:05".

Want a blank editor instead? Open the Go playground.