
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.
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.
- 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) } - 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) } - 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()) } } - 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") } } - 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") } } - 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) } } } - 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) } - 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)) } - 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) } - 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]) } } - 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))) } - 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)) } - 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()) } - 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) } - 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) } } - 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) } } - 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()) } - 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) } - 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) } - 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}) } - 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() } - 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) } - 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)) } - 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.