如何在Go中的fmt.Scanf()之后刷新Stdin?

the*_*T's 5 stdin user-input go

这是一个困扰我的问题.当从用户获得输入时,我想使用循环来要求用户重试,直到他们输入有效输入:

// user_input.go
package main

import (
    "fmt"
)

func main() {
    fmt.Println("Please enter an integer: ")

    var userI int

    for {
        _, err := fmt.Scanf("%d", &userI)
        if err == nil {
            break
        }
        fmt.Println("Sorry, invalid input. Please enter an integer: ")
    }

    fmt.Println(userI)    
}
Run Code Online (Sandbox Code Playgroud)

运行以上操作,如果用户输入有效输入,没问题:

请输入一个整数: 

3

3

退出代码0,正常退出流程.

但是尝试输入一个字符串呢?

请输入一个整数: 
 什么?
对不起,输入无效.请输入一个整数:

抱歉,输入无效.请输入一个整数:

抱歉......

等等,它会逐个字符循环,直到字符串用完为止.即使输入一个字符循环两次,我假设它解析换行符.

无论如何,必须有一种方法在Go中冲洗Stdin?

PS如果没有这样的功能,您将如何解决它以提供相同的功能?我甚至都失败了......

vas*_*man 5

唤醒一个老问题是不是很糟糕?

我更喜欢使用,fmt.Scanln因为A)它不需要导入另一个库(例如阅读器)并且B)它不涉及显式的for循环。

func someFunc() {
    fmt.Printf("Please enter an integer: ")

    // Read in an integer
    var i int
    _, err := fmt.Scanln(&i)
    if err != nil {
            fmt.Printf("Error: %s", err.Error())

            // If int read fails, read as string and forget
            var discard string
            fmt.Scanln(&discard)
            return
    }
    fmt.Printf("Input contained %d", i)
}
Run Code Online (Sandbox Code Playgroud)

然而,似乎应该有一个更优雅的解决方案。特别是在 fmt.Scanln 的情况下,读取在第一个非数字字节之后停止而不是“扫描行”似乎很奇怪。


Ste*_*erg 4

每次失败后,我都会通过阅读直到行尾来解决此问题。这会清除文本的其余部分。

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)
}
Run Code Online (Sandbox Code Playgroud)