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

如何在Go中的fmt.Scanf()之后刷新Stdin?,go,user-input,stdin,Go,User Input,Stdin,现在有一个问题困扰着我。当从用户处获取输入时,我希望使用一个循环,要求用户重试,直到输入有效的输入: // 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

现在有一个问题困扰着我。当从用户处获取输入时,我希望使用一个循环,要求用户重试,直到输入有效的输入:

// 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)    
}
运行上述操作,如果用户输入有效输入,则没有问题:

请输入一个整数:

3

3

退出代码0,进程正常退出。


但是试着输入一个字符串

请输入一个整数: 
什么?
抱歉,输入无效。请输入一个整数:

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

对不起

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

不管怎么说,一定有办法在围棋中冲掉Stdin


另外,如果没有这样的功能,您将如何解决它以提供同等的功能?我甚至失败了…

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

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)
}

我知道这已经得到了回答,但这是我的实施:

func刷新(读卡器*bufio.reader){
变量i int
对于i=0;i

这应该适用于任何情况,包括不能使用“stdin.ReadString('\n')”的情况。

唤醒一个旧问题是否不好

我更喜欢使用
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)
}

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

我在获取用户输入时遇到了类似的问题,但解决方法略有不同。添加到线程以防其他人发现此功能有用:

package main

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

// Get first word from stdin
func getFirstWord() (string) {
    input := bufio.NewScanner(os.Stdin)
    input.Scan()
    ans := strings.Fields(input.Text())

    if len(ans) == 0 {
        return ""
    } else {
        return ans[0]
    }
}

func main() {
    fmt.Printf("Would you like to play a game?\n> ")
    ans := getFirstWord()
    fmt.Printf("Your answer: %s\n", ans)
}

很抱歉,我今天遇到了这个问题,我想通过使用新的标准库功能来改进现有的答案

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

func discardBuffer(r *bufio.Reader) {
    r.Discard(r.Buffered())
}

stdin := bufio.NewReader(os.Stdin)
var i int
for true {
    if _, err := fmt.Fscanln(stdin, &i); err != nil {
        discardBuffer(stdin)
        // Handle error, display message, etc.
        continue
    }
    // Do your other value checks and validations
    break
}
基本思想是始终缓冲从stdin读取的数据。当扫描时遇到错误时,只需丢弃缓冲区内容即可。这样,您就可以从一个空缓冲区开始下一次扫描

或者,您可以在扫描之前丢弃缓冲区,这样用户在此之前的任何杂散输入都不会被拾取

func fscanln(r *bufio.Reader, a ...interface{}) error {
    r.Discard(r.Buffered())
    _, err := fmt.Fscanln(r, a...)
    return err
}

stdin := bufio.NewReader(os.Stdin)
var i int
if err := fscanln(stdin, &i); err != nil {
    // Handle error
}

我使用此代码段过滤不必要的前导空格/新行

in := bufio.NewReader(os.Stdin)
result, err = in.ReadString('\n')
for len(strings.TrimSpace(result)) == 0 {
    result, err = in.ReadString('\n')
}

当然,只需使用
Scanln
,它被记录为占用空白并一直读到新行。