使用fmt.Scan读取空格分隔值时会跳过开头空白并按类型依次读取,直到遇空白;fmt.Scanln类似但换行即止且要求末尾为换行。二者均不支持读含空格的单个字符串,易导致截断或阻塞;应改用bufio.Scanner安全读整行。

用 fmt.Scan 和 fmt.Scanln 读单个或多个空格分隔值时要注意什么
fmt.Scan 会跳过开头所有空白(包括换行、空格、制表符),然后按类型依次读取非空白字符,直到遇到下一个空白;fmt.Scanln 行为类似,但会在换行处停止,且要求输入末尾必须是换行(否则返回 err != nil)。
常见错误:想读一行带空格的字符串,却用了 fmt.Scan,结果只拿到第一个单词。
- 适合场景:读固定数量、空格分隔的整数/字符串,如
3 100 hello - 不支持读含空格的单个字符串(比如用户名 “Alice Smith”)
- 如果输入中有多余空格或换行,
Scan可能卡在等待下一个非空白输入 - 示例:
var a, b int var s string fmt.Scan(&a, &b, &s) // 输入 "12 34 hello world" → a=12, b=34, s="hello","world" 留在缓冲区
用 bufio.Scanner 安全读整行(含空格)的正确姿势
bufio.Scanner 是读整行最常用也最稳妥的方式,默认以 \n 为分隔符,自动丢弃换行符,且对大行有默认 64KB 限制(可调)。
- 必须检查
scanner.Err(),而不仅是scanner.Scan()返回值——IO 错误(如断开连接)不会触发Scan()失败,但会留在Err()中 - 读到的字符串不含末尾换行符,无需再
strings.TrimSpace去 \n(但可能需要去首尾空格) - 若需读超长行,提前调用
scanner.Buffer(make([]byte, 64*1024), 1 扩容 - 示例:
scanner := bufio.NewScanner(os.Stdin) if scanner.Scan() { line := scanner.Text() // 包含中间空格,如 " name age " }
用 strings.Fields 和 strconv.Atoi 拆解并转换多值输入
从 scanner.Text() 或其他来源拿到一整行后,要提取多个值(尤其是数字),别直接 strings.Split(line, " ") ——它会把连续空格拆出空字符串。
这本书给出了一份关于python这门优美语言的精要的参考。作者通过一个完整而清晰的入门指引将你带入python的乐园,随后在语法、类型和对象、运算符与表达式、控制流函数与函数编程、类及面向对象编程、模块和包、输入输出、执行环境等多方面给出了详尽的讲解。如果你想加入 python的世界,David M beazley的这本书可不要错过哦。 (封面是最新英文版的,中文版貌似只译到第二版)
立即学习“go语言免费学习笔记(深入)”;
-
strings.Fields(line)自动按任意空白(空格、\t、\n)切分,且忽略前后及中间多余空白,返回干净的[]string - 逐个转数字时,用
strconv.Atoi而非fmt.Sscanf,前者错误明确、无副作用;后者需严格匹配格式,易因空格失败 - 注意:
Atoi不处理前导空格,但Fields已清理过,可直接用 - 示例:
line := " 123 456 abc " parts := strings.Fields(line) // → []string{"123", "456", "abc"} n1, _ := strconv.Atoi(parts[0]) // 123 n2, _ := strconv.Atoi(parts[1]) // 456
为什么不用 fmt.Scanf 读带空格的字符串
fmt.Scanf("%s", &s) 和 Scan 一样,只读到第一个空白就停;fmt.Scanf("%[^\n]", &s) 理论上能读到换行前所有内容,但实际极易出错:
- 缓冲区残留问题严重:前一次输入的换行可能还在 stdin,导致这次
Scanf立即读到空行 - 格式字符串难写对,比如忘记
%!(MISSING),或没预留足够空间,引发 panic - 无法统一处理错误,
Scanf返回成功读取字段数,但不告诉你哪部分失败 - 跨平台换行符(\r\n vs \n)可能导致截断或阻塞
- 结论:除极简单脚本外,一律优先选
bufio.Scanner+strings.Fields
真正容易被忽略的是 Scanner 的错误检查和缓冲区管理——很多人只写 for scanner.Scan() { ... },却漏掉循环结束后是否该检查 scanner.Err();还有人用默认 Buffer 读日志行,遇到超长路径就 panic。这些不是边缘情况,而是线上真实故障点。









