Go语法及实战笔记1 | 豆包MarsCode AI刷题

153 阅读3分钟

猜数游戏

随机数获取

注意事项

猜数游戏需要程序得到一个随机数作为答案。

package main

import (
	"fmt"
	"math/rand"
)

func main() {
	maxNum := 100
	secretNumber := rand.Intn(maxNum)
	//fmt.Println("The secret number is ", secretNumber)
}

视频课中提到,如果直接运行上述代码,多次运行得到的随机数可能不会变化,并不符合要求。考虑是随机种子没有变化,但在练中学平台上实测每次随机得到的数字都是不一样的。原因在于在Go1.2之后,如果没有手动指定一个种子值,那么会在程序开始时随机生成一个种子值。而在1.2之前是默认用1作为种子值,导致了没有手动指定的情况下每次随机得到的结果都是一个数。但是如果想要得到之前的效果,就加上rand.Seed(1)即可。 但其实在1.2之后,直接调用Seed()来设置种子值的方式已经被弃用了,取而代之的是使用rand.New(NewSource(seed))来生成一个新的本地随机生成器。

randSource := rand.NewSource(time.Now().UnixNano())
// 使用 New 函数创建一个新的随机生成器
random := rand.New(randSource)
secretNumber := random.Intn(maxNum)

问题1: 这样做的原因是什么呢? 可能的答案:直接对全局的随机生成器的种子进行修改可能会在多线程场景下带来潜在风险,因此不如在每个程序内用自己享用的种子生成一个本地的随机生成器,确保安全。

一点小拓展

当前版本只能玩一次游戏就退出了,现在在每次猜对数字后新增一个询问是否开始新一轮的游戏。 如果用户选择新一轮的游戏,就重新获取一个随机数然后继续循环。如果不开始下一轮,就正常退出。

fmt.Println("Do you want to play once again? (y/n)")
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")

switch input {
    case "y":
        secretNumber = rand.Intn(maxNum)
        fmt.Println("New secret number is created")
        fmt.Println("Get a guess")
        continue
    case "n":
        fmt.Println("Bye~")
        break
    default:
        break
				
			}
if input == "n" {
    break
}

另一种读取输入方法

//通过read.ReadString()读取输入
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中,更为简洁。类似于c语言中的scanf
var guess int
_, err := fmt.Scanf("%d", &guess)

在线字典查询

注意事项

运行方式go run ./file.go word

视频中所用到的翻译网站得到的cURL会略有不同,但是源码中的也能正常运行。

cURL to go: curlconverter.com/go/ 这个网站是能够正常打开的

json2go: oktools.net/json2go 已经没法打开了

替代网站: transform.tools/json-to-go 生成的是嵌套的结构体

json2go.dev/ 生产的是没有嵌套的结构体

并发实现同时查询

主要是通过协程的方式来实现,新建两个协程,并用switch语句等待任意一个协程返回结果。 注意此处需要同步对query()函数做适配性修改。并且有一个超时处理用于处理没有返回结果的情况。

ch1 := make(chan DictResponse)
    ch2 := make(chan DictResponse)

    go query(word, ch1)
    go query(word, ch2)
	select {
    case resp := <-ch1:
        fmt.Println("Response from API 1111:")
        fmt.Println(word, "UK:", resp.Dictionary.Prons.En, "US:", resp.Dictionary.Prons.EnUs)
        for _, item := range resp.Dictionary.Explanations {
            fmt.Println(item)
        }
	case resp := <-ch2:
        fmt.Println("Response from API 2222:")
        fmt.Println(word, "UK:", resp.Dictionary.Prons.En, "US:", resp.Dictionary.Prons.EnUs)
        for _, item := range resp.Dictionary.Explanations {
            fmt.Println(item)
        }
    case <-time.After(20 * time.Second):
        fmt.Println("Timeout: No response from either API within 5 seconds")