Search code examples
validationgouser-input

How to handle console input type validation in Go?


I'm trying to build a very basic console inputs for a program using a loop. However, when user inputs something else than an integer, the error message triggers as many times as there are characters in the input string (including newline).

I've tried Scan(), Scanln(), as well as bufio.NewReader() with string parsing, as well as using continue after Println(). All produce the same result.

var threads int

func main() {
    fmt.Println("Enter number of threads:")
    for {
        _, err := fmt.Scanln(&threads)
        if err != nil {
            fmt.Println("Enter a valid number")
        } else {
            break
        }
    }
}

User inputs:

asd

Expected result:

Program: Enter a valid number

Actual result:

Program: Enter a valid number

Program: Enter a valid number

Program: Enter a valid number

Program: Enter a valid number


Solution

  • fmt.Scanln(&threads) throws an error because your first char is already not a valid int, thus there are sd\n still remaining in stdin buffer, this would be my explanation for additional three errors. To avoid this you could just read to string and then use int, err := strconv.Atoi(string) like in code below. Note hereby that fmt.Scan or fmt.Scanln split your userinput until the next space, which is probably not perfect for your usecase. Check out How to read input from console line for some insight in how to choose suiting your usecase.

    package main
    
    import (
        "fmt"
        "strconv"
    )
    
    func main() {
        var s string
        var i int
        fmt.Println("Enter number of threads:")
        for {
            _, err := fmt.Scan(&s)
            i, err = strconv.Atoi(s)
            if err != nil {
                fmt.Println("Enter a valid number")
            } else {
                fmt.Println("Got: " + strconv.Itoa(i))
                break
            }
        }
        //Todo
    }