具有无效浮点数的意外循环



我正在学习Coursera Go课程...挺好的。

在下面的代码中,当用户正确浮点数时,它工作正常。但是当他们输入一些随机字符串时,它会打印错误消息并再次提示每个字符。为什么?

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 floatn")
} else {
return userInput
}
}
}
func main() {
var f float64
f = readFloat("acceleration")
fmt.Printf("You entered: %.04fn", 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:

问题是,如果fmt.Scanf()遇到无效的输入,它将停止使用它。 例如,你想使用%f解析浮点数,但如果用户输入sdffmt.Scanf()会在第一个s字符后知道它是无效的,所以返回一个错误,不会消耗其余的。

所以下一个循环迭代开始,它消耗第二个字符d,这又是无效的,等等。

例如,如果您尝试输入s2,这将变得清晰:

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

第一个s字符无效,但下一次迭代将解析2

"修复"此问题的一种方法是将整行读取为字符串,然后尝试从字符串中解析浮点数。要读取一行,请使用bufio.Scanner,要解析浮点数,请使用strconv.ParseFloat()

下面是如何执行此操作的示例:

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

这是因为如果用户输入错误的值,您的 for 循环是一个无限循环。你应该在fmt.Printf("you entered wrong number")之后有一个return语句,以便 for 循环可以退出。

最新更新