示例代码
package main
import (
"bufio"
"fmt"
"math/rand"
"os"
"strconv"
"strings"
"time"
)
func main() {
maxNum := 100
rand.Seed(time.Now().UnixNano())
secretNumber := rand.Intn(maxNum)
// fmt.Println("The secret number is ", secretNumber)
fmt.Println("Please input your guess")
reader := bufio.NewReader(os.Stdin)
for {
input, err := reader.ReadString('\n')
if err != nil {
fmt.Println("An error occured while reading input. Please try again", err)
continue
}
input = strings.Trim(input, "\r\n")
guess, err := strconv.Atoi(input)
if err != nil {
fmt.Println("Invalid input. Please enter an integer value")
continue
}
fmt.Println("You guess is", guess)
if guess > secretNumber {
fmt.Println("Your guess is bigger than the secret number. Please try again")
} else if guess < secretNumber {
fmt.Println("Your guess is smaller than the secret number. Please try again")
} else {
fmt.Println("Correct, you Legend!")
break
}
}
}
代码分析
这段代码实现了一个简单的猜数字游戏,它的具体逻辑如下:
-
首先导入了必要的包,包括
bufio用于读取输入,fmt用于格式化输出,math/rand用于生成随机数,os用于与操作系统交互,strconv用于字符串和数字类型之间的转换,strings用于字符串处理,time用于获取当前时间。 -
在
main函数中,程序设置了一个最大数字maxNum为100,并使用当前时间的纳秒级Unix时间戳作为随机数生成器的种子,这样可以保证每次运行程序时生成的随机数都不同。 -
然后,程序生成一个0到
maxNum之间的随机数secretNumber,这个数字就是玩家需要猜测的秘密数字。 -
程序提示玩家输入猜测的数字,并使用
bufio.NewReader创建一个读取器reader,用于从标准输入读取玩家的输入。 -
接下来,程序进入一个无限循环,不断读取玩家的输入并进行处理:
-
使用
reader.ReadString('\n')读取一行输入,直到遇到换行符为止。 -
如果读取过程中发生错误,程序会打印错误信息并继续循环,提示玩家重新输入。
-
读取到的输入字符串会被去除首尾的回车和换行符,得到一个干净的数字字符串。
-
然后,程序尝试将这个数字字符串转换为整数
guess,如果转换失败(例如输入的不是数字),程序会打印错误信息并继续循环,提示玩家重新输入。 -
如果转换成功,程序会打印玩家的猜测,并根据猜测的大小给出相应的提示:
- 如果猜测大于秘密数字,程序会提示玩家猜测的数字太大,需要继续尝试。
- 如果猜测小于秘密数字,程序会提示玩家猜测的数字太小,需要继续尝试。
- 如果猜测等于秘密数字,程序会打印祝贺信息并跳出循环,游戏结束。
-
-
游戏结束后,程序会退出。
代码改进
修改代码,使用fmt.Scanf()简化代码实现
package main
import (
"fmt"
"math/rand"
"time"
)
func main() {
maxNum := 100
rand.Seed(time.Now().UnixNano())
secretNumber := rand.Intn(maxNum)
// fmt.Println("The secret number is ", secretNumber)
fmt.Println("Please input your guess")
var guess int
for {
_, err := fmt.Scanf("%d", &guess)
if err!= nil {
fmt.Println("An error occured while reading input. Please try again", err)
continue
}
fmt.Println("You guess is", guess)
if guess > secretNumber {
fmt.Println("Your guess is bigger than the secret number. Please try again")
} else if guess < secretNumber {
fmt.Println("Your guess is smaller than the secret number. Please try again")
} else {
fmt.Println("Correct, you Legend!")
break
}
}
}
简化过程
fmt.Scanf() 是 Go 语言标准库中的一个函数,用于从标准输入(通常是控制台)读取格式化输入。与使用 bufio.NewReader 和 strings.Trim 等操作相比,fmt.Scanf() 可以简化代码实现,因为它直接提供了格式化输入的功能,不需要额外的步骤来处理输入的读取和解析。
在上述代码中,fmt.Scanf() 被用来读取玩家输入的猜测数字。它的使用方式如下:
_, err := fmt.Scanf("%d", &guess)
此处的 %d 是一个格式化动词,表示期望输入一个整数。&guess 是一个指向 int 类型变量的指针,用于接收输入的值。fmt.Scanf() 会阻塞程序执行,等待用户输入一个整数,然后将输入的值存储在 guess 变量中。
如果输入的格式不正确(例如,用户输入了一个非数字字符),fmt.Scanf() 会返回一个错误,通过捕获这个错误用于提示用户重新输入,这就是代码中 if err!= nil 部分的作用。
作为对比,如果使用 bufio.NewReader 和 strings.Trim,需要额外的代码来创建读取器,读取一行输入,然后去除输入字符串的首尾空格。此外,还还需要使用 strconv.Atoi 或其他方法来将字符串转换为整数。这些额外的步骤使得代码更加冗长,而 fmt.Scanf() 则提供了一个更直接和简洁的方式来实现相同的功能。
fmt.Scanf() 通过提供一个直接的格式化输入接口,简化了代码实现,减少了出错的可能性,使代码更加易读和易于维护。