Go course
go programming language icon

Go Exercises: 24 Practice Problems with Solutions

Go is small on purpose, so practice pays off fast. These problems cover slices and maps, strings, multiple return values, error handling, structs, interfaces and the concurrency primitives Go is known for.

Each solution is a complete package main program. Paste it into the editor below and run it; problems reading stdin tell you what to type in the Input box.

Run your answer here

Type your solution, press Run, and use the Input box when a problem asks you to read from standard input.

Go Compiler
Output
Code runs on the Play with Coding execution engine — your code is saved locally for next time.

How to practise so it actually sticks

Attempt the problem before opening the solution, even if your first version is clumsy. A working ugly answer teaches more than a beautiful one you read. When you get stuck for more than five minutes, read the hint — not the solution — and try again.

After you pass, open the solution and ask what is different about it. Shorter? Fewer variables? A built-in you did not know? That comparison is where most of the growth happens. Then change the problem slightly: sort the other direction, handle an empty input, read a value instead of hard-coding it.

Aim for three to five problems a day rather than thirty in one sitting. Spacing practice over days is what moves syntax from "I can look it up" to "my fingers know it".

The exercises

Showing 24 of 24 exercises.

  1. BeginnerBasics & output

    1. Print a greeting

    Store "Ada" in a variable and print "Hello, Ada!".

    Hint: fmt.Printf with %s, or fmt.Println with concatenation.

    package main
    
    import (
    	"fmt"
    )
    
    func main() {
    	name := ""
    }
    Show solution
    package main
    
    import (
    	"fmt"
    )
    
    func main() {
    	name := "Ada"
    	fmt.Printf("Hello, %s!\n", name)
    }
  2. BeginnerBasics & output

    2. Declare and print types

    Declare an int, a float64, a string and a bool, then print each with its type using %T.

    Hint: fmt.Printf("%v %T\n", v, v).

    package main
    
    import (
    	"fmt"
    )
    
    func main() {
    	
    }
    Show solution
    package main
    
    import (
    	"fmt"
    )
    
    func main() {
    	i, f, s, b := 42, 3.14, "go", true
    	fmt.Printf("%v %T\n", i, i)
    	fmt.Printf("%v %T\n", f, f)
    	fmt.Printf("%v %T\n", s, s)
    	fmt.Printf("%v %T\n", b, b)
    }
  3. BeginnerBasics & output

    3. Read a line of input

    Read a name from standard input and greet the user. Type a name in the Input box.

    Hint: bufio.NewScanner(os.Stdin) then Scan and Text.

    package main
    
    import (
    	"bufio"
    	"fmt"
    	"os"
    )
    
    func main() {
    	
    }
    Show solution
    package main
    
    import (
    	"bufio"
    	"fmt"
    	"os"
    )
    
    func main() {
    	sc := bufio.NewScanner(os.Stdin)
    	if sc.Scan() {
    		fmt.Printf("Hello, %s!\n", sc.Text())
    	}
    }
  4. BeginnerConditionals

    4. Even or odd

    Print "even" or "odd" for 17.

    Hint: Go has no ternary; use if/else.

    package main
    
    import (
    	"fmt"
    )
    
    func main() {
    	n := 17
    }
    Show solution
    package main
    
    import (
    	"fmt"
    )
    
    func main() {
    	n := 17
    	if n%2 == 0 {
    		fmt.Println("even")
    	} else {
    		fmt.Println("odd")
    	}
    }
  5. BeginnerConditionals

    5. Switch without break

    Print a grade letter for the score 84 using a switch with conditions.

    Hint: switch { case score >= 90: ... } needs no expression.

    package main
    
    import (
    	"fmt"
    )
    
    func main() {
    	score := 84
    }
    Show solution
    package main
    
    import (
    	"fmt"
    )
    
    func main() {
    	score := 84
    	switch {
    	case score >= 90:
    		fmt.Println("A")
    	case score >= 80:
    		fmt.Println("B")
    	default:
    		fmt.Println("C or below")
    	}
    }
  6. BeginnerLoops

    6. FizzBuzz to 20

    Print 1..20, replacing multiples of 3 with "Fizz", 5 with "Buzz", both with "FizzBuzz".

    Hint: Go has only the for loop — use it as a counting loop.

    package main
    
    import (
    	"fmt"
    )
    
    func main() {
    	for i := 1; i <= 20; i++ {
    	}
    }
    Show solution
    package main
    
    import (
    	"fmt"
    )
    
    func main() {
    	for i := 1; i <= 20; i++ {
    		switch {
    		case i%15 == 0:
    			fmt.Println("FizzBuzz")
    		case i%3 == 0:
    			fmt.Println("Fizz")
    		case i%5 == 0:
    			fmt.Println("Buzz")
    		default:
    			fmt.Println(i)
    		}
    	}
    }
  7. BeginnerSlices & maps

    7. Slice statistics

    For []int{4, 9, 1, 7, 3} print the sum, the largest and the smallest.

    Hint: Range over the slice and keep running values.

    package main
    
    import (
    	"fmt"
    )
    
    func main() {
    	nums := []int{4, 9, 1, 7, 3}
    }
    Show solution
    package main
    
    import (
    	"fmt"
    )
    
    func main() {
    	nums := []int{4, 9, 1, 7, 3}
    	sum, max, min := 0, nums[0], nums[0]
    	for _, n := range nums {
    		sum += n
    		if n > max {
    			max = n
    		}
    		if n < min {
    			min = n
    		}
    	}
    	fmt.Println(sum, max, min)
    }
  8. BeginnerSlices & maps

    8. Grow a slice with append

    Start from an empty slice, append the squares of 1..5 and print it with its length and capacity.

    Hint: append returns a new slice — reassign it.

    package main
    
    import (
    	"fmt"
    )
    
    func main() {
    	var squares []int
    }
    Show solution
    package main
    
    import (
    	"fmt"
    )
    
    func main() {
    	var squares []int
    	for i := 1; i <= 5; i++ {
    		squares = append(squares, i*i)
    	}
    	fmt.Println(squares, len(squares), cap(squares))
    }
  9. IntermediateSlices & maps

    9. Count words with a map

    Count how often each word appears in "to be or not to be".

    Hint: strings.Fields splits on whitespace.

    package main
    
    import (
    	"fmt"
    	"strings"
    )
    
    func main() {
    	
    }
    Show solution
    package main
    
    import (
    	"fmt"
    	"strings"
    )
    
    func main() {
    	text := "to be or not to be"
    	counts := map[string]int{}
    	for _, w := range strings.Fields(text) {
    		counts[w]++
    	}
    	fmt.Println(counts)
    }
  10. IntermediateSlices & maps

    10. Print a map in key order

    Given a map of scores, print the entries sorted by key.

    Hint: Collect the keys into a slice and sort.Strings them.

    package main
    
    import (
    	"fmt"
    	"sort"
    )
    
    func main() {
    	
    }
    Show solution
    package main
    
    import (
    	"fmt"
    	"sort"
    )
    
    func main() {
    	scores := map[string]int{"cy": 88, "ada": 91, "ben": 74}
    	keys := make([]string, 0, len(scores))
    	for k := range scores {
    		keys = append(keys, k)
    	}
    	sort.Strings(keys)
    	for _, k := range keys {
    		fmt.Println(k, scores[k])
    	}
    }
  11. BeginnerStrings

    11. String helpers

    For "Go is expressive" print the upper case form, whether it contains "express", and the word count.

    Hint: strings.ToUpper, strings.Contains, len(strings.Fields(s)).

    package main
    
    import (
    	"fmt"
    	"strings"
    )
    
    func main() {
    	
    }
    Show solution
    package main
    
    import (
    	"fmt"
    	"strings"
    )
    
    func main() {
    	s := "Go is expressive"
    	fmt.Println(strings.ToUpper(s))
    	fmt.Println(strings.Contains(s, "express"))
    	fmt.Println(len(strings.Fields(s)))
    }
  12. IntermediateStrings

    12. Reverse a string safely

    Reverse "golang" by runes so multi-byte characters stay intact.

    Hint: Convert to []rune before swapping ends.

    package main
    
    import (
    	"fmt"
    )
    
    func main() {
    	s := "golang"
    }
    Show solution
    package main
    
    import (
    	"fmt"
    )
    
    func main() {
    	s := "golang"
    	r := []rune(s)
    	for i, j := 0, len(r)-1; i < j; i, j = i+1, j-1 {
    		r[i], r[j] = r[j], r[i]
    	}
    	fmt.Println(string(r))
    }
  13. IntermediateStrings

    13. Build a string efficiently

    Use strings.Builder to join 1..5 into "1-2-3-4-5".

    Hint: Write the separator only when the builder is not empty.

    package main
    
    import (
    	"fmt"
    	"strconv"
    	"strings"
    )
    
    func main() {
    	
    }
    Show solution
    package main
    
    import (
    	"fmt"
    	"strconv"
    	"strings"
    )
    
    func main() {
    	var b strings.Builder
    	for i := 1; i <= 5; i++ {
    		if b.Len() > 0 {
    			b.WriteString("-")
    		}
    		b.WriteString(strconv.Itoa(i))
    	}
    	fmt.Println(b.String())
    }
  14. BeginnerFunctions

    14. Multiple return values

    Write divmod(a, b int) (int, int) returning quotient and remainder, and print both.

    Hint: Go returns tuples natively.

    package main
    
    import (
    	"fmt"
    )
    
    func main() {
    }
    Show solution
    package main
    
    import (
    	"fmt"
    )
    
    func divmod(a, b int) (int, int) {
    	return a / b, a % b
    }
    
    func main() {
    	q, r := divmod(17, 5)
    	fmt.Println(q, r)
    }
  15. IntermediateErrors

    15. Return an error

    Write divide(a, b float64) (float64, error) that refuses division by zero, and handle both cases.

    Hint: errors.New or fmt.Errorf builds the error value.

    package main
    
    import (
    	"errors"
    	"fmt"
    )
    
    func main() {
    }
    Show solution
    package main
    
    import (
    	"errors"
    	"fmt"
    )
    
    func divide(a, b float64) (float64, error) {
    	if b == 0 {
    		return 0, errors.New("cannot divide by zero")
    	}
    	return a / b, nil
    }
    
    func main() {
    	if v, err := divide(10, 4); err == nil {
    		fmt.Println(v)
    	}
    	if _, err := divide(1, 0); err != nil {
    		fmt.Println("error:", err)
    	}
    }
  16. IntermediateErrors

    16. defer and cleanup

    Use defer to print a closing message after the rest of the function has run.

    Hint: Deferred calls run last-in first-out when the function returns.

    package main
    
    import (
    	"fmt"
    )
    
    func main() {
    	
    }
    Show solution
    package main
    
    import (
    	"fmt"
    )
    
    func main() {
    	defer fmt.Println("done")
    	fmt.Println("working")
    	for i := 1; i <= 3; i++ {
    		fmt.Println("step", i)
    	}
    }
  17. IntermediateStructs & interfaces

    17. Structs and methods

    Define a Rect struct with Width and Height plus an Area method, then print the area.

    Hint: func (r Rect) Area() float64 attaches the method.

    package main
    
    import (
    	"fmt"
    )
    
    func main() {
    }
    Show solution
    package main
    
    import (
    	"fmt"
    )
    
    type Rect struct {
    	Width, Height float64
    }
    
    func (r Rect) Area() float64 { return r.Width * r.Height }
    
    func main() {
    	r := Rect{Width: 3, Height: 4}
    	fmt.Println(r.Area())
    }
  18. AdvancedStructs & interfaces

    18. Pointer receiver mutates

    Add a Scale method with a pointer receiver that doubles both sides, and show the change.

    Hint: Only pointer receivers can modify the struct.

    package main
    
    import (
    	"fmt"
    )
    
    func main() {
    }
    Show solution
    package main
    
    import (
    	"fmt"
    )
    
    type Rect struct {
    	W, H float64
    }
    
    func (r *Rect) Scale(f float64) {
    	r.W *= f
    	r.H *= f
    }
    
    func main() {
    	r := Rect{2, 3}
    	r.Scale(2)
    	fmt.Println(r)
    }
  19. AdvancedStructs & interfaces

    19. Satisfy an interface

    Define a Shape interface with Area() and print the total area of a Rect and a Circle.

    Hint: Any type with the right method set satisfies the interface implicitly.

    Show solution
    package main
    
    import (
    	"fmt"
    	"math"
    )
    
    type Shape interface{ Area() float64 }
    
    type Rect struct{ W, H float64 }
    
    func (r Rect) Area() float64 { return r.W * r.H }
    
    type Circle struct{ R float64 }
    
    func (c Circle) Area() float64 { return math.Pi * c.R * c.R }
    
    func main() {
    	shapes := []Shape{Rect{3, 4}, Circle{1}}
    	total := 0.0
    	for _, s := range shapes {
    		total += s.Area()
    	}
    	fmt.Printf("%.2f\n", total)
    }
  20. AdvancedStructs & interfaces

    20. Implement Stringer

    Give a User struct a String() method so fmt prints it in your own format.

    Hint: fmt checks for the String() string method automatically.

    Show solution
    package main
    
    import (
    	"fmt"
    )
    
    type User struct {
    	Name string
    	Age  int
    }
    
    func (u User) String() string { return fmt.Sprintf("%s (%d)", u.Name, u.Age) }
    
    func main() {
    	fmt.Println(User{"Ada", 36})
    }
  21. AdvancedConcurrency

    21. Goroutines and a WaitGroup

    Start five goroutines that each print their number, and wait for all of them.

    Hint: wg.Add(1) before each goroutine, wg.Done() inside, wg.Wait() at the end.

    Show solution
    package main
    
    import (
    	"fmt"
    	"sync"
    )
    
    func main() {
    	var wg sync.WaitGroup
    	for i := 1; i <= 5; i++ {
    		wg.Add(1)
    		go func(n int) {
    			defer wg.Done()
    			fmt.Println("worker", n)
    		}(i)
    	}
    	wg.Wait()
    }
  22. AdvancedConcurrency

    22. Send results over a channel

    Square 1..5 in goroutines, send the results into a channel and sum them.

    Hint: Close the channel once every sender finishes, then range over it.

    Show solution
    package main
    
    import (
    	"fmt"
    	"sync"
    )
    
    func main() {
    	results := make(chan int)
    	var wg sync.WaitGroup
    	for i := 1; i <= 5; i++ {
    		wg.Add(1)
    		go func(n int) {
    			defer wg.Done()
    			results <- n * n
    		}(i)
    	}
    	go func() {
    		wg.Wait()
    		close(results)
    	}()
    	total := 0
    	for v := range results {
    		total += v
    	}
    	fmt.Println(total)
    }
  23. AdvancedAlgorithms

    23. Binary search

    Implement binary search over a sorted slice and print the index of 9, or -1.

    Hint: Keep lo and hi and compare the middle element.

    Show solution
    package main
    
    import (
    	"fmt"
    )
    
    func search(a []int, target int) int {
    	lo, hi := 0, len(a)-1
    	for lo <= hi {
    		mid := (lo + hi) / 2
    		switch {
    		case a[mid] == target:
    			return mid
    		case a[mid] < target:
    			lo = mid + 1
    		default:
    			hi = mid - 1
    		}
    	}
    	return -1
    }
    
    func main() {
    	fmt.Println(search([]int{1, 3, 5, 7, 9, 11}, 9))
    }
  24. IntermediateAlgorithms

    24. Primes below 50

    Print every prime number below 50.

    Hint: Test divisors while d*d <= n.

    package main
    
    import (
    	"fmt"
    )
    
    func main() {
    	
    }
    Show solution
    package main
    
    import (
    	"fmt"
    )
    
    func main() {
    	for n := 2; n < 50; n++ {
    		prime := true
    		for d := 2; d*d <= n; d++ {
    			if n%d == 0 {
    				prime = false
    				break
    			}
    		}
    		if prime {
    			fmt.Print(n, " ")
    		}
    	}
    	fmt.Println()
    }

What to do next

If a whole topic feels shaky, go back to that chapter in the 17-chapter Go course and re-read it, then return here. When the advanced problems feel routine, take the final Go quiz and claim your certificate, or open the Go online compiler and build something of your own.