为什么在有scanf的循环中,为什​​么会得到重复的输出?

When the user enters a wrong number, the code expects to show once the output message but this it's duplicated. why?

note: seems to be something with the scanf inside the loop because if I use scan lonely it works as expected.

Anyway, I can't understand why this behavior

package main

import (
  "fmt"
  "math/rand"
  "time"
)

func main(){
  rand.Seed(time.Now().UnixNano())

  var number int = rand.Intn(99)  
  var input int = 0

  fmt.Println("random: ", number)

  fmt.Println("enter a number: ")
  fmt.Scanf("%d",&input)

  for {
    if number != input {
      fmt.Println("wrong! try again:")
      fmt.Scanf("%d",&input)
      continue
    } else {
      fmt.Println("that's correct!")
      break
    }
  }
}

To accomodate Windows, write fmt.Scanf("%d ", &input):

package main

import (
    "fmt"
    "math/rand"
    "time"
)

func main() {
    rand.Seed(time.Now().UnixNano())

    var number int = rand.Intn(99)
    var input int = 0

    fmt.Println("random: ", number)

    fmt.Println("enter a number: ")
    fmt.Scanf("%d
", &input)

    for {
        if number != input {
            fmt.Println("wrong! try again:")
            fmt.Scanf("%d
", &input)
            continue
        } else {
            fmt.Println("that's correct!")
            break
        }
    }
}

Output:

random:  84
enter a number: 
42
wrong! try again:
42
wrong! try again:
84
that's correct!

Windows uses " " for end-of-line. Linux and others use " " for end-of-line.

You did not check for Scanf errors.

package main

import (
    "fmt"
    "math/rand"
    "time"
)

func main() {
    rand.Seed(time.Now().UnixNano())

    var number int = rand.Intn(99)
    var input int = 0

    fmt.Println("random: ", number)

    fmt.Println("enter a number: ")
    n, err := fmt.Scanf("%d", &input)
    if err != nil {
        fmt.Println(n, err)
    }

    for {
        if number != input {
            fmt.Println("wrong! try again:")
            n, err := fmt.Scanf("%d", &input)
            if err != nil {
                fmt.Println(n, err)
            }
            continue
        } else {
            fmt.Println("that's correct!")
            break
        }
    }
}

Output (Windows):

random:  84
enter a number:
42
wrong! try again:
0 unexpected newline
wrong! try again:
42
wrong! try again:
0 unexpected newline
wrong! try again:
84
that's correct!

Windows Scans "42 " as "42" and " ".

Output (Linux):

random:  84
enter a number: 
42
wrong! try again:
42
wrong! try again:
84
that's correct!

Linux Scans "42 ".

fmt.Scanf will read input alongside the format, if the format doesn't match then the next rune (char) will pass to next input as parameter.

for instance if you have input like abc and you have code like:

    fmt.Scanf("%d", &input)
    // will return 1 error when if failed to parse "a" as integer 
    // and pass "bc" to next input
    // but no other fmt.Scanf so nothing else to be feed with "bc"

and with same input you have the following code:


    fmt.Scanf("%d", &input) 
    // input = 0; error failed to parse "a" as integer 
    // and pass "bc" to next input as parameter

    for {
      if number != input {
        fmt.Println("wrong! try again:")
        fmt.Scanf("%d",&input) 
        // input = 0; error 3 times as 
        // failed to parse "b", "c" as integer
        // and unexpected new line

        continue
      } else {
        fmt.Println("that's correct!")
        break
      }
    }

hopefully it helps.

ref: https://golang.org/pkg/fmt/#Scanf