Thuta Learning
ProjectsProgrammingbeginner

Mini Project: Task Manager (Part 1) - Struct & Slice

Relax. We'll talk through this in plain words — no textbook voice.

What you'll walk away with

  • Apply Mini Project: Task Manager (Part 1) - Struct & Slice in a real, hands-on project
  • Write the code yourself and run it
  • Build an entire project step by step

Let's think about this for a second

In this project we'll combine the concepts you learned in the Basics chapters - struct, slice, function, loop - into a single application. Task Manager is a program that keeps track of a task list right in the terminal, with commands like Add, List, Complete, and Remove. In this Part 1, we'll design the core data structure, the Task struct, and build a list that stores tasks in a slice. In Part 2 and Part 3 we'll keep adding features and gradually build the project out to completion. The main thing to take away from this stage is how a real-world app starts out with its data model.

Let's build it for real

Define a Task struct with ID (int), Title (string), and Done (bool) fields. Inside main(), declare a slice variable called tasks []Task. Write an addTask(tasks []Task, title string) []Task function that appends a new Task and returns the updated slice. Write a listTasks(tasks []Task) function that uses a for range loop to print out the task list along with each item's index, title, and done status. Show the done status using [ ] and [x] formatting.

Code Example

go
package main

import "fmt"

type Task struct {
	ID    int
	Title string
	Done  bool
}

func addTask(tasks []Task, title string) []Task {
	newTask := Task{
		ID:    len(tasks) + 1,
		Title: title,
		Done:  false,
	}
	return append(tasks, newTask)
}

func listTasks(tasks []Task) {
	if len(tasks) == 0 {
		fmt.Println("Task list is empty.")
		return
	}
	for _, t := range tasks {
		status := "[ ]"
		if t.Done {
			status = "[x]"
		}
		fmt.Printf("%s %d. %s\n", status, t.ID, t.Title)
	}
}

func main() {
	var tasks []Task
	tasks = addTask(tasks, "Learn Go basics")
	tasks = addTask(tasks, "Build task manager")
	tasks = addTask(tasks, "Write tests")

	listTasks(tasks)
}
You should see
The terminal will print the 3 tasks as a numbered list, each with a [ ] status marker.

Try it in 5 minutes

Within 5 minutes, call addTask to add up to 5 tasks, then manually set the Done field to true for one task and see how the listTasks output changes.

One quick word of caution

When you pass a slice into a function, append may or may not touch the original slice depending on capacity - so always save the slice the function returns rather than assuming the original got updated.

Easy traps

  • Calling addTask(tasks, title) on its own without writing tasks = addTask(...) to store the return value back into the tasks variable - append does work on the slice, but if you don't save the result back to the original variable, the update never sticks
  • Defining the Task struct's field names in lowercase (id, title), which means files outside the main package can no longer access them - if you want a struct field to be exported, it has to start with an Uppercase letter

Now try it yourself

Within 5 minutes, call addTask to add up to 5 tasks, then manually set the Done field to true for one task and see how the listTasks output changes.

You'll know it worked when: The terminal will print the 3 tasks as a numbered list, each with a [ ] status marker.

Mini Project: Task Manager (Part 1) - Struct & Slice | Thuta Learning