fmt.Scan适合快速测试单值读取但易卡住;读多值用空格或换行分隔;读带空格字符串或整行应选bufio.Scanner;os.Stdin.Read用于精确字节控制;Windows乱码需切UTF-8代码页。

用 fmt.Scan 读单个值最简单,但容易卡住
它适合快速测试或只读一个整数、字符串的场景。但注意:fmt.Scan 会跳过开头所有空白(包括换行),然后一直等到用户输入非空白字符 + 回车才返回。如果上一次输入没清空缓冲区(比如之前用了 fmt.Scanln 或手动读了换行符),这次就会“卡住”,看似没反应。
- 只读一个
int:直接fmt.Scan(&n),n必须是地址 - 读多个值(如两个
int):fmt.Scan(&a, &b),用空格或换行分隔都行 - 别对
string用它来读带空格的句子——它遇到空格就停,实际只读第一个单词
读一行完整输入得用 bufio.Scanner
fmt.Scanln 看似能读一行,但它会把末尾换行符当作分隔符,且不吞掉它;而真实终端输入后按回车,换行符留在缓冲区里,下次读可能立刻拿到空字符串。更稳的方式是 bufio.Scanner,它默认按行切割,自动丢弃换行符,还支持大文本(内部有缓冲)。
- 初始化:先
scanner := bufio.NewScanner(os.Stdin) - 读一行:
if scanner.Scan() { text := scanner.Text() },注意要检查scanner.Err()是否为nil - 别用
scanner.Bytes()直接当字符串用——它返回的是底层切片,如果后续有新扫描,内容可能被覆盖
os.Stdin.Read 适合精确控制字节数,但要自己处理换行
当你需要读固定长度、或者想区分 \r\n 和 \n、或者做粘包处理时,就得绕过封装,直接操作 os.Stdin。它返回原始字节和实际读到的长度,不会帮你切行也不会跳过空白。
- 声明缓冲区:
buf := make([]byte, 256) - 调用:
n, err := os.Stdin.Read(buf),n是实际读入字节数,buf[:n]才是有效内容 - 注意:它不会等回车,只要键盘敲了就可能返回(尤其在非阻塞模式下);Linux/macOS 默认是行缓冲,Windows 控制台行为略有不同
中文输入和编码基本不用操心,但 Windows 控制台可能乱码
Go 源文件默认 UTF-8,os.Stdin 读出来也是原始字节,string(buf) 或 scanner.Text() 都直接转成 UTF-8 字符串。问题通常出在 Windows 的 cmd/powershell 默认代码页是 GBK,而 Go 程序按 UTF-8 解释那些字节,就显示成乱码。
立即学习“go语言免费学习笔记(深入)”;
- 临时解决:启动前执行
chcp 65001(切换到 UTF-8) - 长期方案:用
golang.org/x/sys/windows调用SetConsoleOutputCP(65001),但仅限 Windows - 跨平台稳妥做法:避免依赖控制台编码,改用管道或重定向输入(
echo "你好" | go run main.go总是对的)










