Kiểm tra map nil
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 28 trên 68.
Trong Go, một từ điển có thể có trạng thái đặc biệt gọi là nil. Từ điển nil về cơ bản là một từ điển chưa được khởi tạo và không trỏ đến đâu trong bộ nhớ. Bạn cần hiểu khái niệm này vì nếu cố thêm khóa vào từ điển nil, chương trình sẽ hoảng loạn và gặp sự cố.
Dưới đây là cách một map nil xuất hiện và trông như thế nào:
var myMap map[string]int
// myMap có giá trị nil tại thời điểm nàyKhi khai báo một biến map mà không khởi tạo, Go tự động đặt nó thành nil. Bạn có thể đọc an toàn từ một map nil (nó sẽ trả về giá trị không), nhưng nếu thử ghi vào đó, chương trình sẽ gặp panic:
// Thao tác này an toàn, trả về 0
value := myMap["key"]
// Thao tác này sẽ gây panic!
myMap["key"] = 42Để tránh vấn đề này, bạn luôn nên kiểm tra xem một từ điển có phải là nil hay không trước khi thêm khóa vào đó. Cách kiểm tra rất đơn giản:
if myMap == nil {
myMap = make(map[string]int)
}
myMap["key"] = 42 // Giờ thao tác này đã an toànKiểm tra đơn giản này giúp chương trình không bị lỗi khi làm việc với các từ điển có thể chưa được khởi tạo, giúp code của bạn ổn định và đáng tin cậy hơn.
Thử thách
DễTạo một hệ thống khởi tạo map an toàn để ngăn lỗi panic bằng cách kiểm tra map có nil hay không trước khi ghi dữ liệu. Thử thách này cho thấy tầm quan trọng của việc xác thực trạng thái map trước khi thực hiện các thao tác có thể làm chương trình bị crash.
Bạn sẽ nhận hai đầu vào:
- Một chuỗi biểu thị số thao tác (ví dụ:
"5") - Một chuỗi chứa các thao tác, được phân tách bằng dấu phẩy. Mỗi thao tác nêu tên map mà thao tác đó sử dụng:
"check:[map_name]""init:[map_name]""add:[map_name]:[key]:[value]"
"check:scores,init:scores,add:scores:Alice:95,add:scores:Bob:87,check:grades"
Nhiệm vụ của bạn là:
- Tạo hai biến map có kiểu
map[string]int, tên làscoresvàgrades, nhưng không khởi tạo chúng (chúng sẽ là nil) - Xử lý lần lượt từng thao tác trong chuỗi đầu vào:
- Với thao tác
"check":- Kiểm tra map được chỉ định có nil hay không
- In ra
"Map [map_name] is nil"nếu map là nil - In ra
"Map [map_name] is initialized"nếu map không phải nil
- Với thao tác
"init":- Khởi tạo map được chỉ định bằng
make(map[string]int) - In ra
"Initialized map [map_name]"
- Khởi tạo map được chỉ định bằng
- Với thao tác
"add":- Trước tiên, kiểm tra map có nil hay không
- Nếu map là nil, in ra
"Cannot add to nil map [map_name]" - Nếu map không phải nil, thêm cặp khóa-giá trị rồi in ra
"Added [key]:[value] to [map_name]"
- Phân tích các thao tác bằng cách tách chuỗi đầu vào:
- Tách theo dấu phẩy để lấy từng thao tác riêng lẻ
- Với mỗi thao tác, tách theo dấu hai chấm để lấy loại thao tác và các tham số
- Chuyển chuỗi giá trị thành số nguyên với thao tác add
- Sau khi xử lý tất cả thao tác, hiển thị trạng thái cuối cùng của cả hai map:
- Với mỗi map, nếu map là nil:
"Final state - [map_name]: nil" - Với mỗi map, nếu map đã được khởi tạo:
"Final state - [map_name]: [count] entries", trong đó count là số cặp khóa-giá trị - In
scorestrước vàgradessau, bất kể thứ tự các thao tác đã sử dụng chúng
- Với mỗi map, nếu map là nil:
Dùng package strconv để chuyển chuỗi giá trị thành số nguyên với thao tác add. Thử thách này cho thấy việc kiểm tra map có nil hay không trước khi ghi dữ liệu giúp ngăn lỗi panic khi chạy và làm cho code của bạn vững chắc, đáng tin cậy hơn.
Tự làm thử
package main
import (
"fmt"
"strconv"
"strings"
)
func main() {
// Đọc đầu vào
var numOpsStr string
var operationsStr string
fmt.Scanln(&numOpsStr)
fmt.Scanln(&operationsStr)
// Khai báo các map mà không khởi tạo (chúng sẽ là nil)
var scores map[string]int
var grades map[string]int
// Tách các thao tác theo dấu phẩy
operations := strings.Split(operationsStr, ",")
// TODO: Viết code của bạn bên dưới
// Xử lý lần lượt từng thao tác
// Xử lý các thao tác "check", "init" và "add"
// Với thao tác add, dùng strconv.Atoi() để chuyển chuỗi giá trị thành số nguyên
// In ra trạng thái cuối cùng của cả hai map
// Kiểm tra các map là nil hay đã khởi tạo rồi in ra cho phù hợp
}Bài học này có một bài trắc nghiệm ngắn. Bắt đầu bài học để trả lời và theo dõi tiến độ.
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