
示例工程教程【免费下载链接】learngo❤️ 1000 Hand-Crafted Go Examples, Exercises, and Quizzes. Learn Go by fixing 1000 tiny programs.项目地址https://gitcode.com/gh_mirrors/le/learngo点击查看免费下载这是一篇基于 Learngo 仓库第 22 章「Maps」练习集的技术指南。本章通过三道循序渐进的手写练习带你掌握 Go map 的声明语法、字面量初始化、元素填充与按键查找、多层嵌套 map 的使用以及delete删除与切片复制排序等实战技巧。读完本文并亲手完成练习后你将能独立用 map 组织姓名→电话号码商品 ID→库存状态客户→购物篮这类键值关系型数据。练习集概览与运行方式本练习集位于 22-maps/exercises/共三道练习难度递进Warm Up声明四种不同类型的 map 并打印Populate and Lookup向 map 填充数据并按键查找Hogwarts Students根据命令行传入的学院名返回学生名单每个练习目录下都包含两个文件main.go待补全的题目骨架含完整题目说明注释与solution/main.go参考解答。运行方式统一为go run main.go # 在对应练习目录内执行 go run solution/main.go # 运行参考答案建议先阅读题目文件顶部的注释说明自己动手实现实现受阻或完成后再对照solution/main.go检查差异。在动手前若你对 map 基础语法还不够熟悉可先阅读 22-maps/01-english-dict/02-as-a-map/main.gomap 字面量、nil map、按键取值与 22-maps/02-english-dict-map-populate/main.gomap 填充、覆盖、逗号 ok 惯用法两个教学示例。练习一Warm Up —— 声明并打印四种 map题目要求创建并打印以下四种 map题目文件见 22-maps/exercises/01-warm-up/main.go#键Key元素Element建议类型1姓氏Last name电话号码map[string]string2商品 IDProduct ID是否可售map[int]bool3姓氏Last name多个电话号码map[string][]string4客户 IDCustomer ID商品 ID → 数量map[int]map[int]int关键知识点nil mapGo 中声明 map 变量时若不初始化其零值就是nil。参考解答solution/main.go采用分组声明var ( phones map[string]string products map[int]bool multiPhones map[string][]string basket map[int]map[int]int ) fmt.Printf(phones : %#v\n, phones) fmt.Printf(products : %#v\n, products) fmt.Printf(multiPhones: %#v\n, multiPhones) fmt.Printf(basket : %#v\n, basket)运行后你会看到四个map[...]...类型的空值被%#v打印出来。需要特别注意的是nil map 只能读取、不能写入var dict map[string]string dict[up] yukarı // panic: assignment to entry in nil map这一行为在教学示例 22-maps/01-english-dict/02-as-a-map/main.go 中有明确演示。nil map 的读取是安全的——按键取值会返回元素类型的零值。类型选择的考量第 2 题使用map[int]bool商品 ID 是整数可售状态用布尔值表达直观且节省内存第 3 题map[string][]string一个姓氏对应多个号码元素本身是一个切片这是 map 与切片组合的典型用法第 4 题map[int]map[int]int客户 ID 映射到一张商品 ID → 数量的子 map形成两层嵌套结构。嵌套 map 是本次练习中唯一的难点在下一道练习中你会通过实际操作加深理解。自查要点四个 map 是否分别声明为string、int、string、int类型的键第 3、4 题的元素类型是否分别为[]string和map[int]int能否解释为什么 nil map 打印时不会报错但赋值会崩溃练习二Populate and Lookup —— 填充数据与按键查找题目要求将数据填入第一题声明的 map 中再按键完成四次查找题目见 22-maps/exercises/02-populate/main.go打印 dulin 的电话号码判断商品 ID879401371是否可售打印 greco 的第二个电话号码查询客户101购买商品576872813的数量。参考答案map 字面量初始化参考解答solution/main.go直接用字面量一次性填入全部数据phones : map[string]string{ bowen: 202-555-0179, dulin: 03.37.77.63.06, greco: 03489940240, } products : map[int]bool{ 617841573: true, 879401371: false, 576872813: true, } multiPhones : map[string][]string{ bowen: {202-555-0179}, dulin: {03.37.77.63.06, 03.37.70.50.05, 02.20.40.10.04}, greco: {03489940240, 03489900120}, } basket : map[int]map[int]int{ 100: {617841573: 4, 576872813: 2}, 101: {576872813: 5, 657473833: 20}, 102: {}, }注意multiPhones与basket字面量中省略了元素类型名如{202-555-0179}、{617841573: 4}这是 Go 允许在复合字面量中嵌套省略类型名的写法。四次查找的惯用法查找 1逗号 ok 惯用法who, phone : dulin, N/A if v, ok : phones[who]; ok { phone v } fmt.Printf(%ss phone number: %s\n, who, phone)phones[who]返回两个值元素值与是否存在。若键不存在ok为false此时phone保持默认值N/A。这正是 Go 中判断键是否存在的标准写法。查找 2利用布尔值元素id, status : 879401371, available if !products[id] { status not status } fmt.Printf(Product ID #%d is %s\n, id, status)因为元素本身就是boolproducts[id]直接给出可售状态无需再判断ok。这也提示我们当元素类型的零值如false、、0就能表达缺失语义时可以简化判断逻辑。查找 3先取切片再判断长度who, phone greco, N/A if phones : multiPhones[who]; len(phones) 2 { phone phones[1] } fmt.Printf(%ss 2nd phone number: %s\n, who, phone)先在if初始化语句中把multiPhones[greco]取到局部变量phones再检查长度是否至少为 2安全访问下标phones[1]避免越界。查找 4嵌套 map 的连续取值cid, pid : 101, 576872813 fmt.Printf(Customer #%d is going to buy %d from Product ID #%d.\n, cid, basket[cid][pid], pid)basket[cid]先取到子 map再[pid]取出数量。由于嵌套 map 中的内层键同样遵循缺失返回零值规则即使数据不完整程序也不会崩溃会打印出0——这正是预期输出中空 map 情况下的安全行为。题目埋下的一个陷阱题目要求你完成练习后删除数据并检查程序是否仍然正常工作。这就是在训练你理解当 map 为空或键缺失时上面的写法依然安全输出N/A、not available、0而不会 panic。你可以试着在解答中把字面量全部清空再运行对比输出与题目给出的空 map 预期输出。练习三Hogwarts Students —— 命令行查找 delete 克隆排序题目要求这是本章最综合的一道练习题目见 22-maps/exercises/03-students/main.go用 map 保存霍格沃茨各学院gryffindor、hufflepuf、ravenclaw、slytherin的学生名单通过命令行参数传入学院名打印该学院的学生按姓名排序bobo不属于霍格沃茨要用delete删除不允许手动排序数据且map 中的切片不能被改动提示先复制一份再排序。预期输出$ go run main.go Please type a Hogwarts house name. $ go run main.go bobo Sorry. I dont know anything about bobo. $ go run main.go hufflepuf ~~~ hufflepuf students ~~~ diggory helga scamander wenlock参考答案的完整拆解参考解答位于 solution/main.go分四步第一步字面量构建学院 → 学生切片映射houses : map[string][]string{ gryffindor: {weasley, hagrid, dumbledore, lupin}, hufflepuf: {wenlock, scamander, helga, diggory, bobo}, ravenclaw: {flitwick, bagnold, wildsmith, montmorency}, slytherin: {horace, nigellus, higgs, bobo, scorpius}, bobo: {wizardry, unwanted}, }注意hufflepuf与slytherin的列表中混入了bobo这正是下一步delete的用武之地。第二步删除不属于霍格沃茨的学院delete(houses, bobo)delete(map, key)删除指定键及其元素若键不存在则什么都不做no-op。这一行为在 22-maps/03-internals-cloning/main.go 中有演示delete(dict, awesome) // 删除存在的键 delete(dict, awesome) // 重复删除no-op delete(dict, notexisting) // 删除不存在的键no-op第三步解析命令行参数并查找学院args : os.Args[1:] if len(args) 1 { fmt.Println(Please type a Hogwarts house name.) return } house, students : args[0], houses[args[0]] if students nil { fmt.Printf(Sorry. I dont know anything about %q.\n, house) return }这里利用了一个精妙特性map 取值时若键不存在会返回元素类型的零值。houses[args[0]]找不到时返回nil切片所以students nil即可判断学院不存在不需要额外的ok布尔值。第四步克隆切片后再排序避免修改 map 内部数据clone : append([]string(nil), students...) sort.Strings(clone) fmt.Printf(~~~ %s students ~~~\n\n, house) for _, student : range clone { fmt.Printf(\t %s\n, student) }append([]string(nil), students...)是复制切片的经典一行式把原切片的每个元素逐个追加到空切片上生成一份独立副本。随后对副本sort.Strings排序原 map 中的数据保持原样严格遵守了题目map 内切片不得改动的限制。为什么必须复制再排序map 的元素是引用类型切片时houses[house]返回的切片与原数据共享底层数组。若直接sort.Strings(students)会就地修改 map 内部的切片内容破坏原始数据。题目特意强调这一点就是要训练你养成只读访问 map 中的复合类型时先克隆的防御习惯。延伸map 的内部行为与键类型约束结合本章教学示例本练习集还间接覆盖了几个必须理解的底层规则键类型必须可比较[]int、map这类不可比较类型不能作为键。示例 22-maps/01-english-dict/02-as-a-map/main.go 中注释掉的map[[]int]int与map[map[int]string]bool就是编译错误示范。map 只能用 nil 比较map 之间不能直接用比较只能与nil比较。若要比较两个 map可像 22-maps/02-english-dict-map-populate/main.go 那样借助fmt.Sprintf序列化后比较字符串。增删改查汇总dict[key] value添加或覆盖、value, ok : dict[key]安全取值、delete(dict, key)删除、len(dict)获取键数量、for k, v : range dict遍历。从 map 反向构建另一个 map22-maps/03-internals-cloning/main.go 展示了用make(map[string]string, len(dict))预分配容量并遍历键值、交换键值位置构建反向字典的技巧可扩展练习三做出按学生查学院的版本。总结与进一步探索完成这三道练习你便完整走过了 Go map 的核心生命周期声明nil map→ 字面量/make初始化 → 填充与覆盖 → 按键查找逗号 ok→ 删除 → 遍历 → 嵌套 map 与 map切片组合。参考答案都在各练习目录的solution/main.go中可随时对照。想继续加深理解可以阅读本章其余教学示例切片版 vs map 版英土词典对比在 22-maps/01-english-dict/完成本章问答题 22-maps/questions/README.md 检验概念掌握将 map 与后续章节结合第 23 章「Input Scanning」的 23-input-scanning/02-map-as-sets/main.go 演示了用 map 实现集合去重是 map 在真实程序中最常见的用途之一。赞分享示例工程教程【免费下载链接】learngo❤️ 1000 Hand-Crafted Go Examples, Exercises, and Quizzes. Learn Go by fixing 1000 tiny programs.项目地址https://gitcode.com/gh_mirrors/le/learngo点击查看免费下载相关推荐掌握 Go 短变量声明基于 learngo 仓库的 6 个实战练习详解掌握 Go 短变量声明基于 learngo 仓库的 6 个实战练习详解 Go 的短变量声明 : 是日常编码中使用频率最高的语法之一也是许多初学者最容易示例工程教程Learngo 变量声明热身练习全解11 个入门练习吃透 Go 变量声明、零值与作用域Learngo 变量声明热身练习全解11 个入门练习吃透 Go 变量声明、零值与作用域 本指南基于 learngo 仓库中文翻译版 声明并打印变量练习清单 h示例工程教程从零掌握 Go 简短声明Short Variable Declarationlearngo 六步练习全解与源码验证从零掌握 Go 简短声明Short Variable Declarationlearngo 六步练习全解与源码验证 导读 本文围绕 learngo htt示例工程教程上一篇终极OpenCopilot项目全解析从架构到核心功能的完整指南下一篇如何安装Wplace-BlueMarble3分钟快速上手教程附Chrome/Firefox/Edge浏览器配置创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考