
在使用 Go 语言进行用户交互时,我们经常需要从标准输入(stdin)读取数据。fmt.Scanf 函数是一个常用的选择,但它在处理无效输入时可能会遇到问题,导致程序进入无限循环。本文将介绍如何使用 bufio 包来清空 stdin 输入流,从而避免这种情况。
问题描述
当使用 fmt.Scanf 读取整数时,如果用户输入了非数字字符,fmt.Scanf 会返回一个错误,并且不会从输入流中移除无效字符。这意味着在循环中重复调用 fmt.Scanf 会一直读取到相同的无效字符,导致程序陷入无限循环。
解决方案
解决此问题的关键在于清空 stdin 输入流中的无效字符。我们可以使用 bufio.NewReader 创建一个带缓冲的读取器,然后使用 ReadString('\n') 方法读取并丢弃剩余的输入,直到遇到换行符。
示例代码
package main
import (
"bufio"
"fmt"
"os"
)
func main() {
stdin := bufio.NewReader(os.Stdin)
fmt.Println("Please enter an integer: ")
var userI int
for {
_, err := fmt.Fscan(stdin, &userI)
if err == nil {
break
}
stdin.ReadString('\n') // 清空输入流
fmt.Println("Sorry, invalid input. Please enter an integer: ")
}
fmt.Println(userI)
}代码解释
- stdin := bufio.NewReader(os.Stdin): 创建一个新的 bufio.Reader,它从标准输入读取数据。bufio.Reader 提供了缓冲功能,可以更有效地读取数据。
- fmt.Fscan(stdin, &userI): 使用 fmt.Fscan 函数从 stdin 读取一个整数,并将其存储到 userI 变量中。与 fmt.Scanf 类似,但它从 io.Reader 读取,而不是直接从标准输入读取。
- stdin.ReadString('\n'): 如果 fmt.Fscan 返回错误,说明输入无效。这时,stdin.ReadString('\n') 会读取并丢弃 stdin 中剩余的字符,直到遇到换行符。这有效地清空了输入流,确保下一次循环可以读取新的输入。
注意事项
- 使用 bufio.Reader 可以提高读取效率,特别是在需要频繁读取输入的情况下。
- ReadString('\n') 会一直读取到换行符,因此确保用户输入以换行符结尾。
- 除了 ReadString('\n'),还可以使用其他方法来清空输入流,例如 ReadBytes('\n') 或 ReadByte(),但 ReadString('\n') 通常是最方便的选择。
总结
通过使用 bufio.NewReader 和 ReadString('\n') 方法,我们可以有效地清空 stdin 输入流,解决 fmt.Scanf 在处理无效输入时可能导致的无限循环问题。这种方法可以提高程序的健壮性和用户体验。










