douluogu8713 2019-09-01 19:06
浏览 106
已采纳

意外的循环与无效的浮点数

I'm working through the Coursera Go course ... it's pretty good.

In my code below, it works fine when the user correctly a float. But when they enter some random string, it prints the error message and prompt again for each character. Why is that?

package main

import "fmt"

func readFloat(title string) float64 {
  var userInput float64

  for {
    fmt.Println("Please enter a float: ")
    _, err := fmt.Scanf("%f", &userInput)

    if err != nil {
      fmt.Printf("Wooops! That's not a float
")
    } else {
      return userInput
    }
  }
}

func main() {
  var f float64

  f = readFloat("acceleration")
    fmt.Printf("You entered: %.04f
", f)
}
~/src/coursera/go/course-2-functions-methods/week2 $ go run so.go
Please enter a float:
33.3
You entered: 33.3000
~/src/coursera/go/course-2-functions-methods/week2 $ go run so.go
Please enter a float:
sdf
Wooops! That's not a float
Please enter a float:
Wooops! That's not a float
Please enter a float:
Wooops! That's not a float
Please enter a float:
Wooops! That's not a float
Please enter a float:
  • 写回答

2条回答 默认 最新

  • duan02468 2019-09-01 19:55
    关注

    The problem is that if fmt.Scanf() encounters an invalid input, it will stop consuming it. E.g. you want to parse a float using %f, but if user inputs sdf, fmt.Scanf() will know it's invalid after the first s character, so returns an error and will not consume the rest.

    So the next loop iteration begins, it consumes the second character d, which is again invalid etc.

    If you try to enter s2 for example, this will become clear:

    Please enter a float: 
    s2
    Wooops! That's not a float
    Please enter a float: 
    You entered: 2.0000
    

    First s char is invalid, but the next iteration will parse 2.

    One way to "fix" this is to read a whole line as a string, then attempt to parse a float out of the string. For reading a line, use bufio.Scanner, for parsing a float, use strconv.ParseFloat().

    Here's an example how you can do that:

    func readFloat(title string) float64 {
        scanner := bufio.NewScanner(os.Stdin)
        for {
            fmt.Printf("Please enter a float for %s: ", title)
            if !scanner.Scan() {
                fmt.Println("Error readling line")
                return 0 // Should return an error too!
            }
    
            line := scanner.Text()
            userInput, err := strconv.ParseFloat(line, 64)
            if err == nil {
                return userInput
            }
            fmt.Printf("Wooops! That's not a float
    ")
        }
    }
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?