Go语言实战 | 青训营笔记

99 阅读4分钟

这是我参与「第五届青训营 」伴学笔记创作活动的第 1 天

本节课重点内容

本堂课主要讲述了 Go 语言:

  • 如何构建一个简易的猜谜cli游戏
  • 如何实现一个简单的词典程序

详细知识点

主要涵括了以下知识点

  • Go 语言中,如何获取标准输入
  • Go 语言 for循环 continue,break 关键字
  • Go 语言 代码生成
  • Go 语言 json 序列化与反序列化

实践例子

实现一个简单的猜谜游戏

在 Golang 中可以使用 math/rand 来生成随机数字,为了每次生成不一样的数字,我们应该设置随机数种子。

rand.Seed(time.Now().UnixNano())
secretNum := rand.Intn(100)
fmt.Printf("secretNum is: %v\n", secretNum)

接下来我要尝试捕获用户输入,我们可以通过 bufio.NewReader 来捕获 stdin 输入

reader := bufio.NewReader(os.Stdin)
for {
    input, err := reader.ReadString('\n')
    if err != nil {
        fmt.Printf("err: %v", err)
        continue
    }
    fmt.Printf("input is: %v", input)
}

由于我们读取的参数为 String 我们需使用 strconv.Atoi 将其转换为 Int:

guess, err := strconv.Atoi(input)
if err != nil {
    fmt.Printf("Invalid input, please input a integer number")
    continue
}

接着需要继续编辑逻辑语句,来告诉用户所输入的参数大于还是小于给出的随机值:

if guess > secretNum {
    fmt.Println("your guess is bigger than secret, try again")
} else if guess > secretNum {
    fmt.Println("your guess is smaller than secret, try again")
} else {
    fmt.Println("correct!")
    break
}

从中我们知道了 golang 中如何读取 标准输入(stdin) 以及golang 生成随机数之前需要传入种子,我们一般将程序运行世的nano时间戳作为种子。

实现一个 CLI词典

我们选择的是 fanyi.caiyunapp.com 作为API,首先进入其官网,通过 Console > Network > Xhr 找到其请求地址, 并将其复制为 Curl

image-20230115163747968.png

我们可以通过 curlconverter.comcurl 进行代码生成:

func main() {
    client := &http.Client{}
    var data = strings.NewReader(`{"trans_type": "en2zh", "query": "hello"}`)
    req, err := http.NewRequest("POST", "https://api.interpreter.caiyunai.com/v1/dict", data)
    if err != nil {
        log.Fatal(err)
    }
    req.Header.Set("authority", "api.interpreter.caiyunai.com")
    req.Header.Set("accept", "application/json, text/plain, */*")
    req.Header.Set("accept-language", "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6")
    req.Header.Set("app-name", "xy")
    req.Header.Set("content-type", "application/json;charset=UTF-8")
    req.Header.Set("device-id", "")
    req.Header.Set("dnt", "1")
    req.Header.Set("origin", "https://fanyi.caiyunapp.com")
    req.Header.Set("os-type", "web")
    req.Header.Set("os-version", "")
    req.Header.Set("referer", "https://fanyi.caiyunapp.com/")
    req.Header.Set("user-agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36 Edg/108.0.1462.54")
    req.Header.Set("x-authorization", "token:xxxxxxxxxx")
    resp, err := client.Do(req)
    if err != nil {
        log.Fatal(err)
    }
    defer resp.Body.Close()
    bodyText, err := ioutil.ReadAll(resp.Body)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("%s\n", bodyText)
}

此时请求后, 便会输出 有关 hello 相关的信息。

除此之外,我们需要生成一个 json, 其包含需要请求的单词:

// 结构体
type DictReq struct {
    TransType string `json:"trans_type"`
    Source string `json:"source"`
}

func main() {
    var req := DictReq{
        TransType: "en2zh"
        Source:    "hellp"
    }
    json, err = json.Marshal(req)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Println(json)
}

生成对应的 json 后即可更简单的请求需要的参数,也可以通过第一个实例项目中的 bufio.NewReader(os.Stdin) 来读取用户的标准输入,给出结果.

除此之外,我们还需要对返回的 json 进行反序列化,这样才能读取我们需要的参数 (如中文)。 虽然我知道 有一个更简单的库可以对 json 中指定node进行读取(gjson), 但还是按照所述内容 通过结构体对其进行解析,我们可以通过 oktools.net/json2go 来对返回结构体进行 代码生成

type DistResp struct {
    Rc int `json:"rc"`
    Wiki Wiki `json:"wiki"`
    Dictionary Dictionary `json:"dictionary"`
}
type Description struct {
    Source string `json:"source"`
    Target interface{} `json:"target"`
}
type Item struct {
    Source string `json:"source"`
    Target string `json:"target"`
}
type Wiki struct {
    KnownInLaguages int `json:"known_in_laguages"`
    Description Description `json:"description"`
    ID string `json:"id"`
    Item Item `json:"item"`
    ImageURL string `json:"image_url"`
    IsSubject string `json:"is_subject"`
    Sitelink string `json:"sitelink"`
}
type Prons struct {
    EnUs string `json:"en-us"`
    En string `json:"en"`
}
type Dictionary struct {
    Prons Prons `json:"prons"`
    Explanations []string `json:"explanations"`
    Synonym []string `json:"synonym"`
    Antonym []interface{} `json:"antonym"`
    WqxExample []WqxExample[]string `json:"wqx_example"`
    Entry string `json:"entry"`
    Type string `json:"type"`
    Related []interface{} `json:"related"`
    Source string `json:"source"`
}

func main() {
    var dictResp DictResp
    err := json.Unmarshal(RespBody, &dictResp)
    handleErr(err)
    
    fmt.Println(dictResp)
}

从这个项目,我们学到了 要善于利用代码生成,简化操作。 同时学到了如果对 json 进行反序列化,对map/struct 进行 json 序列化

课后个人总结

Go语言 拥有着丰富的生态,完善的标准库,得益于标准库,很多东西都会在后续的 Go 版本中得到优化,完善。

并且其支持跨平台编译,拥有这远超其他语言的编译速度,也有这完善的 rpc / http 库。因此其很适合开发微服务。

由于其拥有丰富的工具链,包含了 代码格式化 / 编译工具 等,其有着严格的编码规范,所以写出来的代码 风格类似,易于团队协作。

Golang 有着完善的 自动CG功能,开发着不用时刻关注垃圾回收