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

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

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)来实现期望的结果,但得到了相同的结果。

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

package main

import "fmt"

func main() {

	var remainingTickets uint = 50
	var userTickets uint

	fmt.Print("Enter the number of tickets you want to purchase: ")
	fmt.Scan(&userTickets)

	for userTickets > remainingTickets {
		fmt.Printf("We only have %v tickets available!\n", remainingTickets)
		fmt.Print("Try again! Enter the number of tickets: ")
		fmt.Scan(&userTickets)
	}

	for userTickets == 0 {
		fmt.Print("Try again! It must be more than zero: ")
		fmt.Scan(&userTickets)
	}

	fmt.Printf("Remaining tickets: %v\n", remainingTickets-userTickets)

}
英文:

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?

package main

import "fmt"

func main() {

	var remainingTickets uint = 50
	var userTickets uint

	fmt.Print("Enter the number of tickets you want to purchase: ")
	fmt.Scan(&userTickets)

	for userTickets > remainingTickets {
		fmt.Printf("We only have %v tickets available!\n", remainingTickets)
		fmt.Print("Try again! Enter the number of tickets: ")
		fmt.Scan(&userTickets)
	}

	for userTickets == 0 {
		fmt.Print("Try again! It must be more than zero: ")
		fmt.Scan(&userTickets)
	}

	fmt.Printf("Remaining tickets: %v\n", remainingTickets-userTickets)

}

答案1

得分: 1

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

package main

import (
	"fmt"
	"strconv"
)

func main() {

	var remainingTickets uint64 = 50
	
	fmt.Print("请输入您想购买的票数:")

	for {
		var userTickets string
		fmt.Scanln(&userTickets)

		// 解析以确保我们得到一个正(无符号)整数
		u64, err := strconv.ParseUint(userTickets,10,64)
		// 确保它是一个正整数且不等于零
		if err != nil || u64==0{
			fmt.Print("请重试!您必须输入一个大于零的数字:")
			continue
		}

		// 检查剩余票数是否足够
		if u64 > remainingTickets {
			fmt.Printf("我们只剩下 %v 张票!\n", remainingTickets)
			fmt.Print("请重试!请输入票数:")
			continue
		}

		// 更新剩余票数
		remainingTickets -= u64
		break
	}

	fmt.Printf("剩余票数:%d\n", remainingTickets)
}

希望对你有帮助!

英文:

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:

package main

import (
	"fmt"
	"strconv"
)

func main() {

	var remainingTickets uint64 = 50
	
	fmt.Print("Enter the number of tickets you want to purchase: ")

	for {
		var userTickets string
		fmt.Scanln(&userTickets)

		// parse to make sure we get a positive (unsigned) integer
		u64, err := strconv.ParseUint(userTickets,10,64)
		// make sure it's a postive integer and not equal to zero
		if err != nil || u64==0{
			fmt.Print("Try again! You must enter a number greater than zero: ")
			continue
		}

		// check to make sure we have enough tickets left
		if u64 > remainingTickets {
			fmt.Printf("We only have %v tickets available!\n", remainingTickets)
			fmt.Print("Try again! Enter the number of tickets: ")
			continue
		}

		// update remaining tickets
		remainingTickets -= u64
		break
	}

	fmt.Printf("Remaining tickets: %d\n", remainingTickets)
}

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:

确定