Golang中fmt.Scanln输出时为何首字符丢失的问题

Golang中fmt.Scanln输出时为何首字符丢失的问题 在以下代码中,如果用户输入一个字符串,程序会将除第一个字符外的所有字符输出回终端。非常感谢任何帮助理解此异常情况。

Go 版本 1.15

package main

import "fmt"

func main() {
    a := 0
	fmt.Scanln(&a)
	fmt.Println(a)
}

Screenshot from 2022-01-11 14-00-49


更多关于Golang中fmt.Scanln输出时为何首字符丢失的问题的实战教程也可以访问 https://www.itying.com/category-94-b0.html

3 回复

感谢您的解释。干杯。

更多关于Golang中fmt.Scanln输出时为何首字符丢失的问题的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


变量 a 是一个整数,无法存储字符串。fmt.Scanln() 会读取输入的第一个字符,判断这不是一个数字,然后停止继续读取。 程序随后打印 a 的值(仍然是 0)并退出。

此时,Shell 会将剩余的输入作为新命令接管,但找不到该名称的命令,因此报错。

提示:永远不要忽略函数返回的错误。fmt.Scanln() 有两个返回值:成功读取的字符数和一个错误值。(在 Shell 中输入 go doc fmt.Scanln 可获取关于 Scanln 的信息。)

尝试使用 n, err := fmt.Scanln(&a),并在错误不为 nil 时将其打印出来。这样你就能快速看出问题所在。

n, err := fmt.Scanln(&a)
if err != nil {
    fmt.Println(err)
}

这个问题是由于 fmt.Scanln 的输入缓冲区处理导致的。当使用 fmt.Scanln 读取整数时,如果输入包含非数字字符,会导致读取失败并留下未处理的字符在缓冲区中,影响后续读取。

在你的代码中,当输入字符串时,fmt.Scanln(&a) 尝试将输入解析为整数但失败,变量 a 保持为 0,而输入缓冲区中仍保留着完整的字符串。后续的 fmt.Println(a) 输出 0,但程序结束后终端的回显显示了之前缓冲区的内容,造成了首字符“丢失”的错觉。

以下是示例代码演示了缓冲区行为:

package main

import (
	"bufio"
	"fmt"
	"os"
	"strings"
)

func main() {
	reader := bufio.NewReader(os.Stdin)
	
	fmt.Print("输入测试: ")
	input, _ := reader.ReadString('\n')
	input = strings.TrimSpace(input)
	
	fmt.Printf("完整输入: %q\n", input)
	fmt.Printf("首字符: %c\n", input[0])
	fmt.Printf("剩余字符: %q\n", input[1:])
}

要正确处理混合类型输入,可以使用 bufio.Reader

package main

import (
	"bufio"
	"fmt"
	"os"
	"strconv"
	"strings"
)

func main() {
	reader := bufio.NewReader(os.Stdin)
	
	fmt.Print("请输入数字: ")
	input, _ := reader.ReadString('\n')
	input = strings.TrimSpace(input)
	
	num, err := strconv.Atoi(input)
	if err != nil {
		fmt.Println("输入无效:", err)
		return
	}
	
	fmt.Println("读取的数字:", num)
}

对于需要读取整数的场景,建议始终检查 Scanln 的错误返回值:

package main

import "fmt"

func main() {
	var a int
	n, err := fmt.Scanln(&a)
	if err != nil {
		fmt.Printf("读取失败: %v, 成功读取字段数: %d\n", err, n)
		return
	}
	fmt.Println("成功读取:", a)
}
回到顶部