Golang中为什么会出现打印两次的情况?
Golang中为什么会出现打印两次的情况? 大家好!我是Go语言的新手,所以我想,还有什么比创建一个猜数字游戏更好的学习方式呢!
进展相当顺利,能够解析用户输入……但有一件事我实在无法理解。 我有以下代码:
package main
import (
"fmt"
"math/rand"
"strconv"
)
func randRangeInt(min int, max int) int {
return min + rand.Intn(max-min)
}
func validateInput(input string) (int) {
result, err := strconv.Atoi(input)
if err != nil {
return -1
} else {
return result
}
}
func main() {
var secret int = randRangeInt(0, 100)
var userGuess string
fmt.Println("I'm thinking of a number between 0 and 100. Try guessing it:")
fmt.Scanf("%s", &userGuess)
result := validateInput(userGuess)
for result < 0 {
fmt.Println("Try again. Between 0 and 100.")
fmt.Scanf("%s", &userGuess)
result = validateInput(userGuess)
}
if result > -1 {
switch {
case result < secret:
fmt.Println("Your guess is too low")
case result > secret:
fmt.Println("Your guess is too high")
case result == secret:
fmt.Println("That's it!")
}
} else {
panic("Something went wrong")
}
}
在主函数中有一个检查,如果从 validateInput 函数返回的结果小于0(意味着转换时出错),它会再次提示用户输入其他内容。这就是我遇到的问题。当我故意输入非数字内容时,它会提示两次,像这样:

有人能告诉我这是为什么吗?
我知道这可能是个愚蠢的问题,但就像我说的,我刚开始使用Go,这让我很困惑。感谢任何愿意提供帮助的人 🙂
编辑1:我并不是特别想要更好的错误处理或类似的东西(虽然很感谢)。我只是想知道为什么它会打印两次。
更多关于Golang中为什么会出现打印两次的情况?的实战教程也可以访问 https://www.itying.com/category-94-b0.html
这可能与 Windows PowerShell 的工作方式有关。如果你用的是 Mac,可能在使用 zsh?
更多关于Golang中为什么会出现打印两次的情况?的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
这很奇怪。这是我所有的代码,所以如果你无法复现,我也不知道发生了什么。也许是我的 PowerShell 出了问题。
Aronk112:
如果你用的是Mac,可能在使用zsh吧?
是的,我在Mac上使用的是zsh。
Yamil_Bracho:
我得到了和 Aronk112 相同的结果。
嗯……非常有趣。
我的系统是运行 Ventura 的 MacBook Air,测试是通过终端窗口进行的。
我与 Aronk112 得到了相同的结果。我猜它也在验证回车键,所以你可能需要清空标准输入缓冲区。可以尝试使用 fmt.Scanf("%s\r ", &userGuess)。另外,我使用的是 Windows 系统…
fmt.Scanf("%s\r ", &userGuess)
我无法复现你的问题。
$ go run main.go
I'm thinking of a number between 0 and 100. Try guessing it:
-7
Try again. Between 0 and 100.
-100
Try again. Between 0 and 100.
88
Your guess is too high
快速浏览了你的代码后,我无法立即看出为什么会打印两次提示信息。
为了尽可能准确地复现你的结果,我输入了 f 作为我的第一个猜测,和你完全一样。
% go run ./main.go
I'm thinking of a number between 0 and 100. Try guessing it:
f
Try again. Between 0 and 100.
50
Your guess is too low
%
抱歉,这并没有复现出你得到的结果。
我还使用有效的数字作为输入运行了程序,同样,每个响应提示也只出现了一次,而不是两次。这项测试包括猜中了正确的数字。
就是这样。我猜是 Scanf 在 go run ./main.go 之后保留了对回车键的引用(或者它在编译时仍然在内存中?我不太清楚 Go 是如何处理这些事情的。它的内部机制和我习惯的非常不同,所以如果我说了胡话请见谅,而且英语不是我的母语)。通过将第一个 fmt.Scanf("%s", &userGuess) 改为 fmt.Scanf("%s\r", &userGuess),它就能正常工作了。感谢你的建议!
编辑3(还是4?)我用一个预设值进行了测试来对比,它仍然会打印两次,所以这不可能是为了验证 f 字符而按下的回车键(就像我的例子中那样)。
func main() {
fmt.Println("hello world")
}
问题出在 fmt.Scanf("%s", &userGuess) 的缓冲处理上。当输入非数字内容时,validateInput 返回 -1,但输入缓冲区中仍保留着换行符(\n),导致下一次 fmt.Scanf 立即读取到空字符串,从而再次触发错误提示。
以下是修复后的代码示例:
package main
import (
"bufio"
"fmt"
"math/rand"
"os"
"strconv"
"strings"
)
func randRangeInt(min int, max int) int {
return min + rand.Intn(max-min)
}
func validateInput(input string) int {
result, err := strconv.Atoi(strings.TrimSpace(input))
if err != nil {
return -1
}
return result
}
func main() {
rand.Seed(time.Now().UnixNano())
var secret int = randRangeInt(0, 100)
scanner := bufio.NewScanner(os.Stdin)
fmt.Println("I'm thinking of a number between 0 and 100. Try guessing it:")
for scanner.Scan() {
userGuess := scanner.Text()
result := validateInput(userGuess)
if result < 0 {
fmt.Println("Try again. Between 0 and 100.")
continue
}
switch {
case result < secret:
fmt.Println("Your guess is too low")
case result > secret:
fmt.Println("Your guess is too high")
case result == secret:
fmt.Println("That's it!")
return
}
fmt.Println("Guess again:")
}
}
关键修改:
- 使用
bufio.Scanner替代fmt.Scanf,它会自动处理换行符 - 通过
strings.TrimSpace()清理输入 - 简化了循环逻辑,避免重复的输入调用
这样就能确保每次提示只出现一次,同时正确处理各种输入情况。

