Menu
CoddyTech

完成任务

本课属于 Coddy GO 学习旅程的“逻辑与流程”单元。第 23 课,共 68 课。

challenge icon

挑战

简单

在任务管理系统的这一部分,你将实现将任务标记为已完成的功能。本次挑战重点是使用指针接收者修改原始任务数据,展示指针如何让你永久更新结构体字段。

重要提示:由于任务名称可能包含空格(例如 "Buy groceries"),你需要使用 bufio.Scanner 读取完整的输入行。fmt.Scanf 函数会在第一个空格处停止读取,这会导致包含空格的任务名称无法正确读取。请使用 bufio.NewScanner(os.Stdin),并依次调用 scanner.Scan() 和 scanner.Text() 来读取完整的行。

你会收到 3 个输入:

  • 一个表示任务数量的字符串(例如 "4")
  • 一个包含任务数据的字符串,格式为:"name1:status1,name2:status2,name3:status3",其中 status 的值为 "true" 或 "false"(例如 "Buy groceries:false,Call dentist:true,Finish project:false,Review code:false")
  • 一个表示要完成的任务索引的字符串(例如,使用从 0 开始的索引时,"2" 表示第 3 个任务)

你的任务是:

  1. 定义与之前的挑战相同的 Task 结构体,包含 Name(string)和 Completed(bool)字段
  2. 创建一个名为 completeTask 的函数,它接受一个指向 Task 结构体切片的指针,以及一个索引(int)作为参数
  3. 在 completeTask 函数中,将给定索引处任务的 Completed 字段修改为 true
  4. 使用 bufio.Scanner 正确读取输入行:
    • 创建扫描器:scanner := bufio.NewScanner(os.Stdin)
    • 对于每一行输入:先调用 scanner.Scan(),再调用 scanner.Text()
    • 这样可以确保正确读取包含空格的任务名称
  5. 解析第二个输入中的任务数据,创建任务切片:
    • 按逗号拆分输入,获取各个任务条目
    • 对每个条目按冒号拆分,分离名称和状态
    • 将状态字符串转换为布尔值("true" 转换为 true,"false" 转换为 false)
  6. 将第三个输入字符串转换为整数,获取任务索引
  7. 调用你的 completeTask 函数,并传入指向切片的指针和索引
  8. 完成任务后,使用与上一道挑战相同的格式显示所有任务:
    • 对于已完成的任务:"[x] [task_name]"
    • 对于未完成的任务:"[ ] [task_name]"
  9. 打印确认消息:"Task '[task_name]' marked as completed!"
  10. 打印更新后的摘要:"Total: [total_count] tasks ([completed_count] completed, [incomplete_count] remaining)"

使用 strconv 包将索引字符串转换为整数。本次挑战将展示指针接收者如何让你修改原始数据结构,从而永久更改任务列表,并使更改在函数返回后仍然保留。

亲手试试

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)
}

逻辑与流程中的所有课

自己练习: Go 在线编译器