How to clear Stdin after fmt.Scanf () in Go?

Here is the problem that scared me right now. When I get input from a user, I want to use a loop to ask the user to try again until they enter the correct input:

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

Running above, if the user enters the correct input, there is no problem:

Enter an integer:
3

3
exit code 0, the process ends normally.

But try entering a string instead?

Enter an integer: what?
Sorry, invalid input. Enter an integer:
Sorry, invalid input. Enter an integer:
Sorry ...

Etc, , . , , .

, Stdin Go?

P.S. , , ? ...

+5
5

, . .

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

, , :

func flush (reader *bufio.Reader) {
    var i int
    for i = 0; i < reader.Buffered(); i++ {
        reader.ReadByte()
    }
}

, , "stdin.ReadString('\n')" .

+1

?

fmt.Scanln, A) (, ) B), .

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 , , " ".

+1

, . , - :

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

, , , .

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
}

The basic idea is to always buffer your reads from stdin. When you encounter an error while scanning, just discard the contents of the buffer. Thus, you start with an empty buffer for the next scan.

Alternatively, you can drop the buffer before scanning, so any random user input will not be received before.

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
}
0
source

All Articles