Go语法实战个人拓展(词典) | 青训营笔记

114 阅读4分钟

Go语法实战个人拓展(词典) | 青训营笔记

系列介绍

哈哈哈,其实这个系列如题,就是黄同学也参加了这一届青训营😚。作为一名知识内容输出爱好者,我是非常喜欢这个活动的。在接下来的日子里我会持续更新这个系列,希望可以通过这个过程,将我在这次后端青训营的学习过程,尤其是针对课程中知识内容的课下实践,自己的心得体会,知识总结输出到掘金社区。💖

哈哈哈,其实也希望通过这个来对我这种懒狗的一种鞭策。🏅

目前该系列已经发布了:

  1. 👉Go快速上手之基础语法 | 青训营笔记 - 掘金 (juejin.cn) 👈

感兴趣的可以看看🌹

本来第二篇内容应该是实战的笔记,但是我觉得词典拓展的功能比较有趣,所以就决定将这个先分享出来。😙

本文摘要

  1. 通过针对实战练习中 猜谜游戏 以及 词典 的两个实战案例的学习过程中,尤其是针对后者的学习中学到了网络报文(http)相关的知识。黄同学发现词典的最终代码还可以继续完整,结合实例一可以使得更加完整。

1. 词典拓展前(以版本v4为例)

  1. 运行后,根据发送结构体,和响应结构体对象,发送和接收数据,可以实现json解析,序列化和反序列化。
  2. 通过运行指令(运行程序的参数)来规定查询翻译的单词。

可以发现,目前这个 命令行词典 最主要的问题就是每次运行时都需要重新配置参数(如果你和我一样用goland的话),黄同学希望可以一次运行的时候,查询多次,且可以在命令行窗口输入想要查询的单词。

2. 设计与实现

2.1 设计

  1. 查询多次可以使用循环结构,只需要调用 v4 版本的写好的方法query 即可。
  2. 输入,如果弄了猜谜游戏,可以知道里边也有关于输入的实现,稍微修改一下即可。

2.2 优化

  1. ioutl.ReadAll 弃用:

    1. 原因:根据官方文档,这个方法在处理大数据量的读取时(比如网络上的大文件),可能导致应用程序耗内存。
    2. 替代:取而代之的是 io.ReadAll,是一个类似的方法,在读取大量数据时,性能要比ioutil.ReadAll更好更靠。而且这个方法在处理大数据量时,还会使用更少的内存和更小的栈空间。
  2. resp.Body.Close() 缺少错误处理,可以做闭包处理:

        defer func(Body io.ReadCloser) {
            err := Body.Close()
            if err != nil {
                panic(err)
            }
        }(resp.Body)
    

2.3 实现

package main
​
import (
    "bufio"
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
    "os"
    "strings"
)
​
type DictRequest struct {
    TransType string `json:"trans_type"`
    Source    string `json:"source"`
    UserID    string `json:"user_id"`
}
​
type DictResponse struct {
    Rc   int `json:"rc"`
    Wiki struct {
        KnownInLaguages int `json:"known_in_laguages"`
        Description     struct {
            Source string      `json:"source"`
            Target interface{} `json:"target"`
        } `json:"description"`
        ID   string `json:"id"`
        Item struct {
            Source string `json:"source"`
            Target string `json:"target"`
        } `json:"item"`
        ImageURL  string `json:"image_url"`
        IsSubject string `json:"is_subject"`
        Sitelink  string `json:"sitelink"`
    } `json:"wiki"`
    Dictionary struct {
        Prons struct {
            EnUs string `json:"en-us"`
            En   string `json:"en"`
        } `json:"prons"`
        Explanations []string      `json:"explanations"`
        Synonym      []string      `json:"synonym"`
        Antonym      []string      `json:"antonym"`
        WqxExample   [][]string    `json:"wqx_example"`
        Entry        string        `json:"entry"`
        Type         string        `json:"type"`
        Related      []interface{} `json:"related"`
        Source       string        `json:"source"`
    } `json:"dictionary"`
}
​
func query(word string) {
    client := &http.Client{}
    request := DictRequest{TransType: "en2zh", Source: word}
    buf, err := json.Marshal(request)
    if err != nil {
        log.Fatal(err)
    }
    var data = bytes.NewReader(buf)
    req, err := http.NewRequest("POST", "https://api.interpreter.caiyunai.com/v1/dict", data)
    if err != nil {
        log.Fatal(err)
    }
    req.Header.Set("Connection", "keep-alive")
    req.Header.Set("DNT", "1")
    req.Header.Set("os-version", "")
    req.Header.Set("sec-ch-ua-mobile", "?0")
    req.Header.Set("User-Agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.51 Safari/537.36")
    req.Header.Set("app-name", "xy")
    req.Header.Set("Content-Type", "application/json;charset=UTF-8")
    req.Header.Set("Accept", "application/json, text/plain, */*")
    req.Header.Set("device-id", "")
    req.Header.Set("os-type", "web")
    req.Header.Set("X-Authorization", "token:qgemv4jr1y38jyq6vhvi")
    req.Header.Set("Origin", "https://fanyi.caiyunapp.com")
    req.Header.Set("Sec-Fetch-Site", "cross-site")
    req.Header.Set("Sec-Fetch-Mode", "cors")
    req.Header.Set("Sec-Fetch-Dest", "empty")
    req.Header.Set("Referer", "https://fanyi.caiyunapp.com/")
    req.Header.Set("Accept-Language", "zh-CN,zh;q=0.9")
    req.Header.Set("Cookie", "_ym_uid=16456948721020430059; _ym_d=1645694872")
    resp, err := client.Do(req)
    if err != nil {
        log.Fatal(err)
    }
    defer func(Body io.ReadCloser) {
        err := Body.Close()
        if err != nil {
            panic(err)
        }
    }(resp.Body)
    bodyText, err := io.ReadAll(resp.Body)
    if err != nil {
        log.Fatal(err)
    }
    if resp.StatusCode != 200 {
        log.Fatal("bad StatusCode:", resp.StatusCode, "body", string(bodyText))
    }
    var dictResponse DictResponse
    err = json.Unmarshal(bodyText, &dictResponse)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Println(word, "UK:", dictResponse.Dictionary.Prons.En, "US:", dictResponse.Dictionary.Prons.EnUs)
    for _, item := range dictResponse.Dictionary.Explanations {
        fmt.Println(item)
    }
}
​
func main() {
    fmt.Println("You could translate no more than 10 times")
    reader := bufio.NewReader(os.Stdin)
    for i := 0; i < 10; i++ {
        fmt.Println("Please input a word you want translate. You could input -1 if you want break")
        word, err := reader.ReadString('\n')
        if err != nil {
            fmt.Println("An error occured while reading input. Please try again", err)
            continue
        }
        word = strings.Trim(word, "\r\n")
        if word == "-1" {
            break
        }
        fmt.Println("word:", word)
        query(word)
    }
}

参考资料

黄同学在编写这篇文章,除了自己的实践外,还参考了不少资料。如果朋友想要通过我的这篇简陋笔记文章去探索那些可以称为宝玉或者 💎 般的知识,不妨通过下面的链接看看:

  1. ioutil package - io/ioutil - Go Packages
  2. Go 语言的实战案例 - 掘金 (juejin.cn)