为什么 fmt.Scan() 的行为表现奇怪?

huangapple go评论97阅读模式
英文:

Why does fmt.Scan() behave in a weird way?

问题

我正在尝试验证用户输入。如果用户输入一个整数,它会按预期工作。然而,如果用户输入一个非整数的字符串,变量userTickets会被赋值为0,但会打印出多次Try again! It must be more than zero: 。确切地说,它会打印len(input)次,我不明白为什么会这样。

我还尝试使用fmt.Scanf("%d", &usertickets)来实现期望的结果,但得到了相同的结果。

为什么会出现这种行为,我该如何编写一个解决方法?

  1. package main
  2. import "fmt"
  3. func main() {
  4. var remainingTickets uint = 50
  5. var userTickets uint
  6. fmt.Print("Enter the number of tickets you want to purchase: ")
  7. fmt.Scan(&userTickets)
  8. for userTickets > remainingTickets {
  9. fmt.Printf("We only have %v tickets available!\n", remainingTickets)
  10. fmt.Print("Try again! Enter the number of tickets: ")
  11. fmt.Scan(&userTickets)
  12. }
  13. for userTickets == 0 {
  14. fmt.Print("Try again! It must be more than zero: ")
  15. fmt.Scan(&userTickets)
  16. }
  17. fmt.Printf("Remaining tickets: %v\n", remainingTickets-userTickets)
  18. }
英文:

I'm trying to validate the user input. If the user inputs an integer number it works like expected. However, if the user inputs a non-integer string, the variable userTickets gets assigned value 0, but prints Try again! It must be more than zero: many times. To be exact, it prints len(input) times and I don't understand why.

Also tried achieving desired result using fmt.Scanf("%d", &usertickets) but got an identical result.

Why does it behave this way and how can I write a workaround for it?

  1. package main
  2. import "fmt"
  3. func main() {
  4. var remainingTickets uint = 50
  5. var userTickets uint
  6. fmt.Print("Enter the number of tickets you want to purchase: ")
  7. fmt.Scan(&userTickets)
  8. for userTickets > remainingTickets {
  9. fmt.Printf("We only have %v tickets available!\n", remainingTickets)
  10. fmt.Print("Try again! Enter the number of tickets: ")
  11. fmt.Scan(&userTickets)
  12. }
  13. for userTickets == 0 {
  14. fmt.Print("Try again! It must be more than zero: ")
  15. fmt.Scan(&userTickets)
  16. }
  17. fmt.Printf("Remaining tickets: %v\n", remainingTickets-userTickets)
  18. }

答案1

得分: 1

Scan能够在不读取stdin的全部内容的情况下确定输入不是数字。这就是为什么当输入非数字时,验证逻辑会循环len(input)次的原因。虽然你也可以使用Scanner(人们确实推荐这种方法),但下面是一个类似于你的方法的实现。请注意,所有的验证检查都在一个单独的"for"循环中完成:

  1. package main
  2. import (
  3. "fmt"
  4. "strconv"
  5. )
  6. func main() {
  7. var remainingTickets uint64 = 50
  8. fmt.Print("请输入您想购买的票数:")
  9. for {
  10. var userTickets string
  11. fmt.Scanln(&userTickets)
  12. // 解析以确保我们得到一个正(无符号)整数
  13. u64, err := strconv.ParseUint(userTickets,10,64)
  14. // 确保它是一个正整数且不等于零
  15. if err != nil || u64==0{
  16. fmt.Print("请重试!您必须输入一个大于零的数字:")
  17. continue
  18. }
  19. // 检查剩余票数是否足够
  20. if u64 > remainingTickets {
  21. fmt.Printf("我们只剩下 %v 张票!\n", remainingTickets)
  22. fmt.Print("请重试!请输入票数:")
  23. continue
  24. }
  25. // 更新剩余票数
  26. remainingTickets -= u64
  27. break
  28. }
  29. fmt.Printf("剩余票数:%d\n", remainingTickets)
  30. }

希望对你有帮助!

英文:

Scan is able to determine that the input isn't numeric without reading the entire contents of stdin. This is why you validation logic loops for len(input) when non-numeric. While you can use a Scanner as well (and people do recommend that approach), below is an approach similar to yours. Note that all validation checking is done within a single "for" loop as well:

  1. package main
  2. import (
  3. "fmt"
  4. "strconv"
  5. )
  6. func main() {
  7. var remainingTickets uint64 = 50
  8. fmt.Print("Enter the number of tickets you want to purchase: ")
  9. for {
  10. var userTickets string
  11. fmt.Scanln(&userTickets)
  12. // parse to make sure we get a positive (unsigned) integer
  13. u64, err := strconv.ParseUint(userTickets,10,64)
  14. // make sure it's a postive integer and not equal to zero
  15. if err != nil || u64==0{
  16. fmt.Print("Try again! You must enter a number greater than zero: ")
  17. continue
  18. }
  19. // check to make sure we have enough tickets left
  20. if u64 > remainingTickets {
  21. fmt.Printf("We only have %v tickets available!\n", remainingTickets)
  22. fmt.Print("Try again! Enter the number of tickets: ")
  23. continue
  24. }
  25. // update remaining tickets
  26. remainingTickets -= u64
  27. break
  28. }
  29. fmt.Printf("Remaining tickets: %d\n", remainingTickets)
  30. }

huangapple
  • 本文由 发表于 2022年2月6日 18:44:48
  • 转载请务必保留本文链接:https://go.coder-hub.com/71006364.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定