
本文讲解 Go 语言中读取标准输入(stdin)多字段文本行的正确方法,指出 fmt.Scanln 的局限性,并推荐使用 bufio.Scanner 配合 strings.Fields 实现健壮、逐行、空格分隔的字段解析。
本文讲解 go 语言中读取标准输入(stdin)多字段文本行的正确方法,指出 `fmt.scanln` 的局限性,并推荐使用 `bufio.scanner` 配合 `strings.fields` 实现健壮、逐行、空格分隔的字段解析。
在 Go 中,fmt.Scanln 并非按“整行”读取,而是按空白分隔的字段(token) 读取——它遇到第一个空格就停止,因此 echo "A 1 2 3 4" | go run test.go 中只捕获到 "A",后续数字被遗留在输入缓冲区,导致行为不符合预期。strings.Fields() 本身作用是按任意空白字符(空格、制表符、换行符等)分割字符串并自动去除前后空格和空字段,但它依赖上游提供完整的行内容,而 Scanln 无法满足这一前提。
✅ 正确做法是使用 bufio.Scanner:它专为逐行读取设计,能完整获取一行(不含换行符),且对输入流友好、高效、安全(默认单行上限 64KB,可配置)。配合 strings.Fields() 即可精准拆解空格分隔的多个字段。
以下是推荐实现:
package main
import (
"fmt"
"os"
"bufio"
"strings"
)
func main() {
scanner := bufio.NewScanner(os.Stdin)
for scanner.Scan() {
line := scanner.Text() // 完整读取一行(无换行符)
fmt.Printf("Got line: %q\n", line)
fields := strings.Fields(line) // 按空白分割,自动清理空字段
for i, field := range fields {
fmt.Printf("field[%d]: %q\n", i, field)
}
}
if err := scanner.Err(); err != nil {
fmt.Fprintf(os.Stderr, "reading input failed: %v\n", err)
}
}
? 关键说明与注意事项:
-
bufio.Scanner是处理标准输入的首选方案,比fmt.Scan*系列更可控、更可靠; -
strings.Fields()会将" A 1\t2\n3 "规范化为[]string{"A", "1", "2", "3"},无需手动 Trim 或正则; - 若需保留空字段(如
"a,,b"中的空串),应改用strings.Split(line, " ")并自行 Trim,但通常Fields更符合命令行输入语义; -
scanner.Scan()返回false时,请务必检查scanner.Err()判断是否因 I/O 错误终止,避免静默失败。
该模式适用于解析日志行、CLI 输入、配置片段等典型场景,兼具简洁性与生产可用性。










