Hoàn thành một việc cần làm
Thuộc phần Logic và luồng điều khiển trong hành trình GO của Coddy. Bài học 23 trên 68.
Thử thách
DễTrong phần này của hệ thống quản lý công việc, bạn sẽ triển khai khả năng đánh dấu công việc là đã hoàn thành. Thử thách này tập trung vào việc dùng bộ nhận (receiver) con trỏ để sửa đổi dữ liệu công việc gốc, qua đó cho thấy con trỏ giúp bạn cập nhật vĩnh viễn các trường của struct như thế nào.
Lưu ý quan trọng: Vì tên công việc có thể chứa dấu cách (như "Buy groceries"), bạn cần dùng bufio.Scanner để đọc toàn bộ dòng đầu vào. Hàm fmt.Scanf ngừng đọc ở dấu cách đầu tiên, khiến tên công việc có dấu cách bị đọc sai. Hãy dùng bufio.NewScanner(os.Stdin) rồi gọi scanner.Scan() và tiếp theo là scanner.Text() để đọc trọn dòng.
Bạn sẽ nhận được ba đầu vào:
- Một chuỗi biểu thị số lượng công việc (ví dụ:
"4") - Một chuỗi chứa dữ liệu công việc theo định dạng:
"name1:status1,name2:status2,name3:status3", trong đó trạng thái là"true"hoặc"false"(ví dụ:"Buy groceries:false,Call dentist:true,Finish project:false,Review code:false") - Một chuỗi biểu thị chỉ số của công việc cần hoàn thành (ví dụ:
"2"cho công việc thứ ba, dùng chỉ số bắt đầu từ 0)
Nhiệm vụ của bạn:
- Định nghĩa struct
Taskgiống như trong các thử thách trước, với các trườngName(chuỗi) vàCompleted(bool) - Tạo hàm có tên
completeTask, nhận tham số là con trỏ đến một lát cắt gồm các structTaskvà một chỉ số (int) - Bên trong hàm
completeTask, sửa trườngCompletedcủa công việc tại chỉ số đã cho thànhtrue - Dùng
bufio.Scannerđể đọc đúng các dòng đầu vào:- Tạo scanner:
scanner := bufio.NewScanner(os.Stdin) - Với mỗi dòng đầu vào: gọi
scanner.Scan(), sau đó gọiscanner.Text() - Cách này giúp đọc chính xác tên công việc có dấu cách
- Tạo scanner:
- Phân tích dữ liệu công việc từ đầu vào thứ hai để tạo lát cắt công việc:
- Tách đầu vào theo dấu phẩy để lấy từng mục công việc
- Với mỗi mục, tách theo dấu hai chấm để phân biệt tên và trạng thái
- Chuyển chuỗi trạng thái thành giá trị boolean (
"true"trở thànhtrue,"false"trở thànhfalse)
- Chuyển chuỗi đầu vào thứ ba thành số nguyên để lấy chỉ số công việc
- Gọi hàm
completeTaskvới con trỏ đến lát cắt và chỉ số đó - Sau khi hoàn thành công việc, hiển thị tất cả công việc theo cùng định dạng như thử thách trước:
- Với công việc đã hoàn thành:
"[x] [task_name]" - Với công việc chưa hoàn thành:
"[ ] [task_name]"
- Với công việc đã hoàn thành:
- In thông báo xác nhận:
"Task '[task_name]' marked as completed!" - In bản tổng kết đã cập nhật:
"Total: [total_count] tasks ([completed_count] completed, [incomplete_count] remaining)"
Dùng package strconv để chuyển chuỗi chỉ số thành số nguyên. Thử thách này cho thấy bộ nhận con trỏ cho phép bạn sửa đổi cấu trúc dữ liệu gốc như thế nào, giúp các thay đổi trong danh sách công việc được lưu lại sau khi hàm trả về.
Tự làm thử
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)
}Tất cả bài học trong Logic và luồng điều khiển
1Luồng điều khiển nâng cao
Switch với `fallthrough`Thoát khỏi vòng lặp lồng nhauTiếp tục một vòng lặp cụ thểCâu lệnh `goto`Ôn tập: điều khiển vòng lặp nâng cao4Dự án: Danh sách việc cần làm đơn giản
Thiết lập dự ánThêm một việc cần làm2Struct và phương thức
Định nghĩa phương thức cho structReceiver giá trịReceiver con trỏChọn receiverPhương thức và hàmÔn tập: hành vi của struct5Tìm hiểu chuyên sâu về map
Map chứa structCon trỏ làm giá trị của mapKiểm tra map nilSo sánh các mapÔn tập: bộ đếm tần suất từ8Dự án: Quản lý hàng tồn kho đơn giản
Tổng quan dự ánKiểm tra hàng tồn kho3Interface (cơ bản)
Interface là gì?Định nghĩa interfaceTriển khai interfaceDùng kiểu interfaceInterface rỗngKhẳng định kiểuType switchÔn tập: hình dạng và hành viTự luyện tập: Trình biên dịch Go online