Golang中如何理解Donovan和Kernighan书里的输入处理
Golang中如何理解Donovan和Kernighan书里的输入处理 大家好,Golang社区!
我是Go语言的新手,最近开始阅读Donovan和Kernighan的《Go程序设计语言》。在第一章(第1章,第3节)讨论从标准输入中查找重复行时,我遇到了以下代码:
func main() {
counts := make(map[string]int)
input := bufio.NewScanner(os.Stdin) // 这一行
for input.Scan() { // 还有这一行
counts[input.Text()]++
}
for line, n := range counts {
if n > 1 {
fmt.Printf("%d\t%s\n", n, line)
}
}
}
作为一名具备一些C语言知识的Python开发者,我对我注释的那两行代码感到困惑。在Python和C这类语言中,使用像 input() 和 scanf() 这样的函数来获取用户输入是很直接的,但Go的处理方式似乎有所不同。有人能帮我理解一下这几行代码在Go中是如何工作的吗?
感谢您的帮助!
更多关于Golang中如何理解Donovan和Kernighan书里的输入处理的实战教程也可以访问 https://www.itying.com/category-94-b0.html
在Go中,bufio.NewScanner和Scan()方法提供了一种高效处理流式输入的方式,这与C的scanf()或Python的input()的交互式输入模式有本质区别。
关键点解析:
-
bufio.NewScanner(os.Stdin)创建了一个带缓冲的扫描器,包装了标准输入流。缓冲机制减少了系统调用次数,提升读取性能。 -
input.Scan()是核心方法,它会:- 读取直到下一个分隔符(默认是
\n) - 返回
bool表示是否成功读取 - 将读取的内容存储在扫描器内部缓冲区
- 遇到EOF或错误时返回
false
- 读取直到下一个分隔符(默认是
-
input.Text()获取Scan()读取到的字符串内容
工作流程示例:
package main
import (
"bufio"
"fmt"
"os"
)
func main() {
scanner := bufio.NewScanner(os.Stdin)
lineNumber := 0
// 持续扫描直到EOF(Ctrl+D或Ctrl+Z)
for scanner.Scan() {
lineNumber++
text := scanner.Text()
fmt.Printf("Line %d: %s\n", lineNumber, text)
}
// 检查扫描错误(非EOF错误)
if err := scanner.Err(); err != nil {
fmt.Fprintln(os.Stderr, "Reading error:", err)
}
}
与C/Python的对比:
// Go的Scanner方式(流式)
scanner := bufio.NewScanner(os.Stdin)
for scanner.Scan() {
line := scanner.Text()
// 处理每一行
}
// Python的input()方式(交互式)
while True:
try:
line = input()
except EOFError:
break
// C的scanf()方式(格式化)
char buffer[256];
while (scanf("%255[^\n]", buffer) == 1) {
// 处理每行
}
高级用法示例:
// 自定义分隔符
scanner := bufio.NewScanner(os.Stdin)
scanner.Split(bufio.ScanWords) // 按单词扫描
// 读取大文件
file, _ := os.Open("data.txt")
defer file.Close()
scanner := bufio.NewScanner(file)
buffer := make([]byte, 0, 64*1024)
scanner.Buffer(buffer, 1024*1024) // 设置1MB缓冲区
for scanner.Scan() {
process(scanner.Bytes()) // 直接访问字节切片,避免字符串分配
}
错误处理要点:
scanner := bufio.NewScanner(os.Stdin)
for {
if !scanner.Scan() {
if scanner.Err() != nil {
// 真正的错误(如读取失败)
log.Fatal("Scan error:", scanner.Err())
}
// EOF,正常结束
break
}
data := scanner.Text()
// 处理数据
}
这种设计让Go能够统一处理各种输入源(文件、网络、标准输入),同时保持内存效率和性能。Scanner会自动处理缓冲、内存分配和错误边界,比直接使用os.Stdin.Read()更安全高效。


