单词计数 – 永夜 https://www.shuijingwanwq.com 没有不值得去解决的问题,也没有不值得去学习的技术! Thu, 16 Apr 2026 07:21:40 +0000 zh-Hans hourly 1 https://wordpress.org/?v=7.0 Go语言入门练习:Maps 实现单词计数(WordCount) https://www.shuijingwanwq.com/2026/04/16/9534/ https://www.shuijingwanwq.com/2026/04/16/9534/#comments Thu, 16 Apr 2026 07:17:38 +0000 https://www.shuijingwanwq.com/?p=9534 浏览量: 322

作为Go语言入门的基础练习,Maps(映射)的使用是重点知识点之一,而单词计数(WordCount)练习则是巩固Maps用法的经典案例。本文将详细记录该练习的实现过程、核心思路、代码解析,以及练习中涉及的关键知识点,适合和我一样正在自学Go语言的参考,也作为自己的学习记录存档。

一、练习需求说明
本次练习的核心需求是实现一个名为WordCount的函数,该函数接收一个字符串参数s,返回一个map[string]int类型的值,其中key是字符串中的每个“单词”,value是该单词在字符串中出现的次数。
练习提供了基础代码框架,同时提示可以使用strings.Fields函数辅助实现,最终通过wc.Test函数运行测试套件,验证函数实现的正确性。
初始基础代码如下:

package main

import (
	"golang.org/x/tour/wc"
)

func WordCount(s string) map[string]int {
	return map[string]int{"x": 1} // 占位代码,需完善
}

func main() {
	wc.Test(WordCount)
}

二、核心思路梳理
要实现单词计数,核心需要完成3个步骤,思路清晰且贴合Go语言的特性:

  1. 创建一个空的映射(map),用于存储单词和对应的计数,map的键为string类型(单词),值为int类型(计数);
  2. 将输入的字符串按“单词”分割,这里借助strings.Fields函数,自动处理空白字符(空格、制表符、换行符等),分割后得到单词切片;
  3. 遍历单词切片,对每个单词进行计数,每遇到一次该单词,就将map中对应的值加1,最终返回这个映射。

三、完善后的完整代码
结合上述思路,完善后的代码如下,关键步骤已添加注释,便于理解:

package main

import (
	"strings" // 导入 strings 包,使用 Fields 函数分割单词

	"golang.org/x/tour/wc"
)

// WordCount 统计字符串中每个单词的出现次数
func WordCount(s string) map[string]int {
	// 1. 创建一个空的 map,用于存储单词和对应的计数
	wordMap := make(map[string]int)

	// 2. 使用 strings.Fields 分割字符串,按空格/制表符/换行符分割成单词切片
	words := strings.Fields(s)

	// 3. 遍历单词切片,统计每个单词的数量
	for _, word := range words {
		wordMap[word]++ // 单词每出现一次,对应计数 +1
	}

	// 4. 返回统计结果
	return wordMap
}

func main() {
	// 运行测试函数,验证 WordCount 是否正确
	wc.Test(WordCount)
}

四、关键知识点解析
本次练习重点考察Go语言中Maps的使用,同时涉及strings包的基础用法,以下是核心知识点的详细解析,帮助加深理解:

  1. Maps 的初始化与使用
    Go语言中,map的初始化有两种方式:一种是直接使用map字面量(如初始代码中的map[string]int{“x”: 1}),适合已知初始键值对的场景;另一种是使用make函数(make(map[string]int)),适合初始为空、后续动态添加键值对的场景,也是本次练习的首选方式。
    特别注意:当访问map中不存在的键时,不会报错,会返回该值类型的默认值(int类型默认值为0),这也是我们能够直接使用wordMap[word]++的原因——第一次遇到某个单词时,其对应的值为0,++后变为1,后续再次遇到则依次累加。
  2. strings.Fields 函数的作用
    strings.Fields函数是Go语言标准库中strings包的常用函数,其作用是将字符串按“空白字符”分割,返回一个字符串切片([]string)。这里的空白字符包括空格、制表符(\t)、换行符(\n)等,并且会自动忽略连续的空白字符,无需我们手动处理多余空格,极大简化了单词分割的逻辑。
    举个例子:若输入字符串为”hello world go”(world和go之间有两个空格),strings.Fields处理后得到的切片是[“hello”, “world”, “go”],自动过滤了多余的空格,非常适合单词计数场景。
  3. 循环遍历切片
    本次练习中使用for range循环遍历单词切片,for range循环是Go语言中遍历切片、map等集合的常用方式,语法为for 索引, 值 := range 集合。这里我们只需要用到切片中的“值”(即单词),所以将索引用下划线(_)忽略,避免未使用变量的编译错误。

五、测试结果与验证
完善代码后,运行程序,wc.Test函数会自动执行一系列测试用例,验证WordCount函数的正确性。如果实现正确,控制台会输出“PASS”,表示所有测试用例都通过;若存在错误,则会输出具体的错误信息,提示哪个测试用例未通过,便于我们排查问题。
比如,当输入字符串为”I am learning Go Go”时,函数应返回map[string]int{“I”:1, “am”:1, “learning”:1, “Go”:2},测试套件会自动验证该结果是否正确。如图1

完善代码后,运行程序,wc.Test函数会自动执行一系列测试用例,验证WordCount函数的正确性。
/app/go-tour # cd exercise-maps/
/app/go-tour/exercise-maps # go run main.go 
PASS
 f("I am learning Go!") = 
  map[string]int{"Go!":1, "I":1, "am":1, "learning":1}
PASS
 f("The quick brown fox jumped over the lazy dog.") = 
  map[string]int{"The":1, "brown":1, "dog.":1, "fox":1, "jumped":1, "lazy":1, "over":1, "quick":1, "the":1}
PASS
 f("I ate a donut. Then I ate another donut.") = 
  map[string]int{"I":2, "Then":1, "a":1, "another":1, "ate":2, "donut.":2}
PASS
 f("A man a plan a canal panama.") = 
  map[string]int{"A":1, "a":2, "canal":1, "man":1, "panama.":1, "plan":1}

六、学习心得
这个练习看似简单,却覆盖了Go语言中Maps的核心用法、strings包的基础函数以及循环遍历的技巧,非常适合入门阶段巩固知识点。
对于刚开始自学Go语言的我来说,通过这个练习,不仅掌握了map的初始化、键值对的添加和修改,还学会了借助标准库函数简化开发流程——不需要自己手动分割字符串、处理空白字符,体现了Go语言“简洁、高效”的设计理念。
另外,通过编写注释、梳理思路,也加深了对代码的理解,后续遇到类似的计数场景(如统计字符出现次数),也能快速复用本次练习的思路。

七、拓展思考
如果想进一步拓展这个练习,可以尝试以下需求,巩固更多知识点:

  1. 忽略大小写统计:比如将“Go”和“go”视为同一个单词,可通过strings.ToLower或strings.ToUpper函数将单词统一转为小写或大写后再计数;
  2. 处理标点符号:比如字符串中包含“hello,”“world!”,需要去除标点符号后再统计单词;
  3. 统计最长单词:在计数的同时,记录出现次数最多的单词和其出现次数。
]]>
https://www.shuijingwanwq.com/2026/04/16/9534/feed/ 1