Completing a Task
Part of the Logic & Flow section of Coddy's GO journey — lesson 23 of 68.
Challenge
EasyIn this part of your task management system, you'll implement the ability to mark tasks as complete. This challenge focuses on using pointer receivers to modify the original task data, demonstrating how pointers allow you to update struct fields permanently.
Important Note: Since task names may contain spaces (like "Buy groceries"), you'll need to use bufio.Scanner to read entire lines of input. The fmt.Scanf function stops reading at the first space, which would break task names with spaces. Use bufio.NewScanner(os.Stdin) and call scanner.Scan() followed by scanner.Text() to read complete lines.
You will receive three inputs:
- A string representing the number of tasks (e.g.,
"4") - A string containing task data in the format:
"name1:status1,name2:status2,name3:status3"where status is either"true"or"false"(e.g.,"Buy groceries:false,Call dentist:true,Finish project:false,Review code:false") - A string representing the index of the task to complete (e.g.,
"2"for the third task, using 0-based indexing)
Your task is to:
- Define the same
Taskstruct from previous challenges withName(string) andCompleted(bool) fields - Create a function called
completeTaskthat takes a pointer to a slice ofTaskstructs and an index (int) as parameters - Inside the
completeTaskfunction, modify theCompletedfield of the task at the given index totrue - Use
bufio.Scannerto read the input lines properly:- Create a scanner:
scanner := bufio.NewScanner(os.Stdin) - For each input line: call
scanner.Scan()thenscanner.Text() - This ensures task names with spaces are read correctly
- Create a scanner:
- Parse the task data from the second input to create your slice of tasks:
- Split the input by commas to get individual task entries
- For each entry, split by colon to separate the name and status
- Convert the status string to a boolean (
"true"becomestrue,"false"becomesfalse)
- Convert the third input string to an integer to get the task index
- Call your
completeTaskfunction with a pointer to your slice and the index - After completing the task, display all tasks using the same format as the previous challenge:
- For completed tasks:
"[x] [task_name]" - For incomplete tasks:
"[ ] [task_name]"
- For completed tasks:
- Print a confirmation message:
"Task '[task_name]' marked as completed!" - Print the updated summary:
"Total: [total_count] tasks ([completed_count] completed, [incomplete_count] remaining)"
Use the strconv package to convert the index string to an integer. This challenge demonstrates how pointer receivers enable you to modify the original data structure, making permanent changes to your task list that persist after the function returns.
Try it yourself
package main
import (
"bufio"
"fmt"
"os"
"strconv"
"strings"
)
type Task struct {
Name string
Completed bool
}
func viewAllTasks(tasks []Task) {
for _, task := range tasks {
if task.Completed {
fmt.Printf("[x] %s\n", task.Name)
} else {
fmt.Printf("[ ] %s\n", task.Name)
}
}
}
func main() {
var numTasksStr string
fmt.Scanln(&numTasksStr)
numTasks, _ := strconv.Atoi(numTasksStr)
scanner := bufio.NewScanner(os.Stdin)
scanner.Scan()
taskData := scanner.Text()
var tasks []Task
taskEntries := strings.Split(taskData, ",")
for _, entry := range taskEntries {
parts := strings.Split(entry, ":")
if len(parts) >= 2 {
name := parts[0]
completed, _ := strconv.ParseBool(parts[1])
task := Task{
Name: name,
Completed: completed,
}
tasks = append(tasks, task)
}
}
viewAllTasks(tasks)
completedCount := 0
for _, task := range tasks {
if task.Completed {
completedCount++
}
}
incompleteCount := numTasks - completedCount
fmt.Printf("Total: %d tasks (%d completed, %d remaining)\n", numTasks, completedCount, incompleteCount)
}All lessons in Logic & Flow
1Advanced Control Flow
Switch with `fallthrough`Breaking from Nested LoopsContinuing a Specific LoopThe `goto` StatementRecap - Advanced Loop Control4Project: Simple Task List
Project SetupAdding a Task2Structs and Methods
Defining Methods on StructsValue ReceiversPointer ReceiversChoosing ReceiversMethods vs FunctionsRecap - Struct Behavior5Maps In-Depth
Maps of StructsPointers as Map ValuesTesting for Nil MapsComparing MapsRecap - Word Frequency Counter3Interfaces (The Basics)
What is an Interface?Defining an InterfaceImplementing an InterfaceUsing Interface TypesEmpty InterfaceType AssertionsType SwitchRecap - Shapes and Behaviors