Scan()输入函数
package main
import "fmt"
func main() {
var a int
var b string
for {
fmt.Println("请输入一个整数和一个字符串(用空格分隔):")
fmt.Scan(&a, &b) // 直接读取输入到变量中
fmt.Println("整数:", a)
fmt.Println("字符串:", b)
}
}
正确的运行结果:
有问题的运行结果(第一种情况):
为什么当我第一次输入123然后点击Enter键,再输入456然后点击Enter键,控制台正确打印出了结果,但是当我第二次输入qwe然后点击Enter键后,直接在控制台输出了上一次的结果,并且是连续输出多个?
出现这种现象的原因是 fmt.Scan 函数在读取输入时发生了错误,并且没有处理错误的情况。当输入数据格式不符合预期时,例如输入 “qwe” 而不是一个整数和一个字符串,fmt.Scan 会返回一个错误,导致读取失败。由于错误没有被处理,程序会继续循环,并且变量 a 和 b 保留了上一次的值,从而导致上一次的结果被重复输出。
具体原因分析
1.第一次输入正确
:
- 你输入了 “123”,按下 Enter 键,然后再输入 “456”,按下 Enter。fmt.Scan 成功读取到整数 123 和字符串 “456”,并赋值给变量 a 和 b。
- 程序输出:
整数: 123
字符串: 456
2.第二次输入不符合预期
:
- 你输入了 “qwe” 并按下 Enter。此时,fmt.Scan 尝试读取一个整数和一个字符串,但输入的 “qwe” 无法解析为整数,因此 fmt.Scan 返回一个错误,并且 a 和 b 保留了之前的值 123 和 “456”。
- 因为程序没有检查并处理读取失败的情况,导致循环继续进行,重复输出上一次的结果。
3.连续输出
:
- 当 fmt.Scan 读取失败时,它不会从输入缓冲区中移除错误的输入(如 “qwe”),因此在下一次循环中再次读取时,仍然读取到 “qwe”,导致重复发生错误,输出同样的内容。
解决方法
需要在读取输入失败时进行错误处理,并清除输入缓冲区中的错误数据。可以使用 bufio.NewReader 来清空缓冲区,以确保下次读取时不会受之前错误输入的影响。
下面是修改后的代码示例:
package main
import (
"bufio"
"fmt"
"os"
)
func main() {
var a int
var b string
reader := bufio.NewReader(os.Stdin) // 创建一个 bufio.Reader 来清除缓冲区
for {
fmt.Println("请输入一个整数和一个字符串(用空格分隔):")
_, err := fmt.Scan(&a, &b)
if err != nil {
fmt.Println("输入格式不正确,请重新输入")
// 清除缓冲区中的剩余内容
reader.ReadString('\n')
continue
}
fmt.Println("整数:", a)
fmt.Println("字符串:", b)
}
}
修改说明
1.当输入格式不正确时,程序会提示 “输入格式不正确,请重新输入”,并使用 reader.ReadString(‘\n’) 来清除输入缓冲区中剩余的内容。
2.如果读取成功,则会输出当前的 a 和 b。
总结
出现连续输出的问题是因为 fmt.Scan 在输入格式错误时,未能正确处理错误并清除输入缓冲区。通过添加错误处理和清除输入缓冲区的操作,可以避免这种情况的发生。
当 fmt.Scan 读取失败时,既然它不会从输入缓冲区中移除错误的输入(如 “qwe”),因此在下一次循环中再次读取时,仍然读取到 “qwe”,导致重复发生错误,输出同样的内容。那为什么只是重复输出了3次,而不是一直重复输出下去呢?
出现这种现象的原因在于输入缓冲区的行为和 fmt.Scan 的工作原理。每次调用 fmt.Scan,它都会尝试读取输入缓冲区中的数据并解析为指定的格式(例如整数和字符串)。当输入格式不符合要求时,fmt.Scan 会返回一个错误,并且不会从缓冲区中移除无法解析的内容,因此导致错误的输入被多次重复读取。
但是,为什么这种重复只发生了3次而不是无限次呢?这可能是因为终端的输入缓冲区管理的行为和系统处理输入的方式。以下是可能的解释:
1.输入缓冲区的限制
:
- 操作系统或终端在处理输入缓冲区时,可能会对输入尝试的次数做出限制。如果连续多次读取失败,它可能会触发某种输入错误处理机制,导致程序的行为变化。
2.标准输入的阻塞行为
:
- 当使用 fmt.Scan 时,它会阻塞等待用户输入。虽然输入流中有残留数据(例如 “qwe”),但经过一定次数的错误读取后,可能输入流被清理,或者终端要求重新输入。因此,程序会暂停,等待用户输入新的数据。
3.自动错误处理机制
:
- 某些终端会自动进行错误数据的处理,或者根据缓冲区中的内容进行自动清空。当检测到多次重复输入失败时,可能会重置缓冲区的状态。
因此,尽管在程序逻辑上看起来应该无限循环,但因为终端或缓冲区管理的机制,导致这种重复输出的次数有限。
有问题的运行结果(第二种情况):
Scanln()输入函数
package main
import "fmt"
func main() {
var a int
var b string
for {
fmt.Println("请输入一个整数和一个字符串(用空格分隔,并按回车结束):")
fmt.Scanln(&a, &b) // 直接读取输入到变量中
fmt.Println("整数:", a)
fmt.Println("字符串:", b)
}
}
正确的结果:
错误的结果: