写Go代码的语言语句时候,从终端读数据这件事,输入比想象中要绕一点。语言语句很多语言里一个 scanf 就搞定的输入事,Go 偏偏给你留了好几个入口,语言语句选错了要么读不干净,输入要么卡在那儿不动。语言语句
最常用的输入是
fmt.Scan系列。它按空白字符切分,语言语句空格、输入换行都算分隔符。语言语句看个例子:var name string var age int fmt.Scan(&name,输入 &age) fmt.Println(name, age)输入
Tom 25,回车,语言语句它读到 Tom 和 25。输入看起来挺顺。语言语句问题出在混合输入上。假如你先用 Scan 读了一个整数,再用bufio去读一整行,那个换行符还留在缓冲区里,下一次读取直接拿到空字符串。这个坑我踩过不止一次。所以实际项目里,我更倾向用
bufio.NewReader(os.Stdin)。它能按行读,控制权在你手里:reader := bufio.NewReader(os.Stdin) line, _ := reader.ReadString('\n') line = strings.TrimSpace(line)TrimSpace这一步别省。Windows 上换行是\r\n,不处理的话字符串末尾会多一个\r,拿去比较或者解析数字都会出错。有人用strings.TrimRight(line, "\r\n"),效果一样,看个人习惯。读一整行之后往往还要拆成多个字段。这时候
strings.Fields很好用,它按任意空白切分,不管中间有几个空格:parts := strings.Fields(line) a, _ := strconv.Atoi(parts[0]) b, _ := strconv.Atoi(parts[1])这种写法在算法题里特别常见,因为输入格式经常是“一行若干个数”,用 Scan 逐个读反而容易和后面的行读取打架。
另一个容易被忽略的是
fmt.Scanln。它和 Scan 的区别在于遇到换行就停,不会继续往下读。但它的行为有点怪:如果一行里参数没填满,它会把剩余参数置零并返回错误。很多人以为 Scanln 就是“读一行”,其实不是。真正读一行还是得靠 bufio。说到错误处理,
fmt.Scan的返回值经常被忽略。它返回成功扫描的项数和错误。输入 “abc” 给一个 int 变量,扫描项数是 0,err 非 nil。如果不检查,变量保持零值,程序继续跑,后面逻辑全乱。我见过有人调试半天,最后发现是输入类型不匹配但没报错。如果输入量很大,比如几十万行,
bufio.Scanner比ReadString更合适。它内部有缓冲区,默认 64KB,按行切分效率高。用法也简单:scanner := bufio.NewScanner(os.Stdin) for scanner.Scan() { line := scanner.Text() // 处理 }不过 Scanner 有个默认行长度限制,单行超过 64KB 会报
bufio.Scanner: token too long。遇到超长行得手动调scanner.Buffer扩大缓冲。这个限制平时碰不到,一旦碰到就很懵。选哪个?我的习惯是:算法题、小工具,bufio.NewReader 加 ReadString 足够;需要逐行流式处理大文件或大量输入,用 Scanner;只有确定输入格式非常规整、全是空白分隔的简单场景,才用 fmt.Scan。混用多种读取方式时,尤其要小心缓冲区里残留的换行符——这是 Go 输入处理里最常翻车的地方。
顶: 232踩: 252






评论专区