Menu
CoddyTech

检查 nil 映射

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

在 Go 中,映射可以有一种特殊状态,称为 nil。nil 映射本质上是尚未初始化的映射,它在内存中没有指向任何位置。理解这个概念很重要,因为尝试向 nil 映射添加键会导致程序触发恐慌并崩溃。

下面介绍 nil 映射是如何出现的,以及它是什么样子:

var myMap map[string]int
// 此时 myMap 为 nil

声明映射变量时,如果不对其进行初始化,Go 会自动将其设为 nil。你可以安全地从 nil 映射中读取数据(它会返回零值),但尝试写入会导致程序崩溃:

// 这样是安全的,会返回 0。
value := myMap["key"]

// 这样会触发 panic!
myMap["key"] = 42

为避免这个问题,在尝试向映射中添加键之前,你应该始终检查映射是否为 nil。检查很简单:

if myMap == nil {
    myMap = make(map[string]int)
}
myMap["key"] = 42 // 现在这样就安全了

这个简单的检查可以确保程序在处理可能尚未初始化的映射时不会崩溃,让你的代码更加健壮、可靠。

challenge icon

挑战

简单

创建一个安全的映射初始化系统,在执行写入操作前检查映射是否为 nil,从而避免程序崩溃。这个挑战展示了在执行可能导致程序崩溃的操作前验证映射状态的重要性。

你会收到两个输入:

  • 一个表示操作数量的字符串(例如 "5")
  • 一个包含多个操作的字符串,各操作之间用逗号分隔。每个操作都会指定要处理的映射:
    • "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"

你的任务是:

  1. 创建两个 map[string]int 类型的映射变量,分别命名为 scores 和 grades,但不要初始化它们(它们将为 nil)
  2. 按顺序处理输入字符串中的每个操作:
  3. 对于 "check" 操作:
    • 检查指定的映射是否为 nil
    • 如果映射为 nil,打印 "Map [map_name] is nil"
    • 如果映射不为 nil,打印 "Map [map_name] is initialized"
  4. 对于 "init" 操作:
    • 使用 make(map[string]int) 初始化指定的映射
    • 打印 "Initialized map [map_name]"
  5. 对于 "add" 操作:
    • 先检查映射是否为 nil
    • 如果映射为 nil,打印 "Cannot add to nil map [map_name]"
    • 如果映射不为 nil,添加键值对并打印 "Added [key]:[value] to [map_name]"
  6. 通过拆分输入字符串来解析操作:
    • 按逗号拆分,获取各个操作
    • 对每个操作按冒号拆分,获取操作类型和参数
    • 对于 add 操作,将值字符串转换为整数
  7. 处理完所有操作后,显示两个映射的最终状态:
    • 对于每个映射,如果它为 nil:"Final state - [map_name]: nil"
    • 对于每个映射,如果它已初始化:"Final state - [map_name]: [count] entries",其中 count 是键值对的数量
    • 先打印 scores,再打印 grades,无论操作中使用它们的顺序如何

使用 strconv 包将 add 操作中的值字符串转换为整数。这个挑战展示了在执行写入操作前检查映射是否为 nil,如何避免运行时崩溃,并让代码更加健壮可靠。

亲手试试

package main

import (
	"fmt"
	"strconv"
	"strings"
)

func main() {
	// 读取输入
	var numOpsStr string
	var operationsStr string
	fmt.Scanln(&numOpsStr)
	fmt.Scanln(&operationsStr)
	
	// 声明映射但不初始化(它们的值为 nil)
	var scores map[string]int
	var grades map[string]int
	
	// 按逗号拆分 operations
	operations := strings.Split(operationsStr, ",")
	
	// TODO: 在下方编写你的代码
	// 依次处理每个操作
	// 处理 "check"、"init" 和 "add" 操作
	// 对于 add 操作,使用 strconv.Atoi() 将值字符串转换为整数
	
	// 输出两个映射的最终状态
	// 检查映射是 nil 还是已初始化,并据此输出
}
quiz icon自我测试

这节课包含一个小测验。开始学习即可作答,并记录你的进度。

逻辑与流程中的所有课

自己练习: Go 在线编译器