基础知识 | 青训营笔记

130 阅读4分钟

基础知识 | 青训营笔记

这是我参与「第三届青训营 -后端场」笔记创作活动的的第2篇笔记

开发环境win10/wsl2, vscode+go插件,主要总结三个实战部分

1 简介

1.1 特点

高性能、高并发

语法简单、学习曲线平缓

丰富的标准库

完善的工具链

静态链接

快速编译:微服务编译速度1min、增量编译小于1s

跨平台

垃圾回收

2 实战入门

2.1 猜数字

v1版本:

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

使用rand.Intn()生成随机数,但是每次生成数字都相同

使用当前时间作为随机种子,从而生成每次不同的数字

v2:

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

v3版本增加了获取用户输入,使用bufio.NewReader读取一行内容

reader := bufio.NewReader(os.Stdin)
input, err := reader.ReadString('\n')
input = strings.TrimSuffix(input, "\n")//删除最后换行符

顺便总结一下其他获取标准输入方式

//bufio.NewScanner读取一行
input := bufio.NewScanner(os.Stdin)
input.Scan()
str := input.Text()
//Scanln读取一行
var n string
fmt.Scanln(&n)
//Scanf
var guess int
fmt.Scanf("%d", &guess)

2.2 翻译

使用post请求将需要翻译的内容发送给彩云翻译,根据返回的Response获取翻译结果

在翻译界面右键->检查->network找到对应的post请求

image-20220507170717302

payload与preview分别是Request内容与Response内容

image-20220507170842306

image-20220507170905556

获取Request内容

对翻译请求copy curl并将其粘贴到curlconverter.com/#go中获取golan…

package main

import (
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"strings"
)

func main() {
	client := &http.Client{}
	var data = strings.NewReader(`{"trans_type":"en2zh","source":"good"}`)
	req, err := http.NewRequest("POST", "https://api.interpreter.caiyunai.com/v1/dict", data)
	if err != nil {
		log.Fatal(err)
	}
	req.Header.Set("Accept", "application/json, text/plain, */*")
	req.Header.Set("Accept-Language", "zh-CN,zh;q=0.9,zh-TW;q=0.8,en-US;q=0.7,en;q=0.6")
	req.Header.Set("Connection", "keep-alive")
	req.Header.Set("Content-Type", "application/json;charset=UTF-8")
	req.Header.Set("Origin", "https://fanyi.caiyunapp.com")
	req.Header.Set("Referer", "https://fanyi.caiyunapp.com/")
	req.Header.Set("Sec-Fetch-Dest", "empty")
	req.Header.Set("Sec-Fetch-Mode", "cors")
	req.Header.Set("Sec-Fetch-Site", "cross-site")
	req.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.54 Safari/537.36")
	req.Header.Set("X-Authorization", "token:qgemv4jr1y38jyq6vhvi")
	req.Header.Set("app-name", "xy")
	req.Header.Set("os-type", "web")
	req.Header.Set("sec-ch-ua", `" Not A;Brand";v="99", "Chromium";v="101", "Google Chrome";v="101"`)
	req.Header.Set("sec-ch-ua-mobile", "?0")
	req.Header.Set("sec-ch-ua-platform", `"Windows"`)
	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)
}

将请求封装为struct,并使用json.Marshal序列化

type DictRequest struct {
	TransType string `json:"trans_type"`
	Source    string `json:"source"`
	UserID    string `json:"user_id"`
}
...
request := DictRequest{TransType: "en2zh", Source: "good"}
	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)
	}

获取Response结构体

复制preview内容至oktools.net/json2go转换出R…

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"`
}

将获取到的bodyText反序列化得到Response并输出需要的内容

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)
	}

作业相关

需求:增加另外一种翻译方式并并行翻译

尝试有道翻译

有道翻译的请求为form data格式而非彩云翻译的json格式

image-20220507172829184

i=good&from=AUTO&to=AUTO&smartresult=dict&client=fanyideskweb&salt=16519067160016&sign=49d2f830da995315a642d51046ffe008&lts=1651906716001&bv=247811f9b7fd387f154bf67d8ebd44f3&doctype=json&version=2.1&keyfrom=fanyi.web&action=FY_BY_REALTlME

直接拼接字符串,我在实现时还是定义了结构体,使用reflect对遍历结构体每个Field并拼接进字符串

type youdaoResponse struct {
	TranslateResult [][]struct {
		Tgt string `json:"tgt"`
		Src string `json:"src"`
	} `json:"translateResult"`
	ErrorCode   int    `json:"errorCode"`
	Type        string `json:"type"`
	SmartResult struct {
		Entries []string `json:"entries"`
		Type    int      `json:"type"`
	} `json:"smartResult"`
}
...
request := youdaoRequest{
		i:           word,
		from:        "AUTO",
		to:          "AUTO",
		smartresult: "dict",
		client:      "fanyideskweb",
		salt:        "16519067160016",
		sign:        "49d2f830da995315a642d51046ffe008",
		lts:         "1651906716001",
		bv:          "247811f9b7fd387f154bf67d8ebd44f3",
		doctype:     "json",
		version:     "2.1",
		keyfrom:     "fanyi.web",
		action:      "FY_BY_REALTlME",
	}
	body := ""
	v := reflect.ValueOf(request)
	t := reflect.TypeOf(request)
	for i := 0; i < v.NumField(); i++ {
		if i != 0 {
			body += "&"
		}
		body += t.Field(i).Name + "=" + v.Field(i).String()
	}
	data := strings.NewReader(body)
	client := &http.Client{}
	req, err := http.NewRequest("POST", "https://fanyi.youdao.com/translate_o?smartresult=dict&smartresult=rule", data)
...

并行翻译部分直接起两个协程即可,使用waitgroup等待两个协程运行结束后再退出。

使用printChan保证同一时间只输出一个结果,防止交叉输出结果

func main() {
	var word string
	if len(os.Args) != 2 {
		fmt.Fprintf(os.Stderr, `usage: simpleDict WORD
		example: simpleDict hello
				`)
		os.Exit(1)
	}
	var wg sync.WaitGroup
	printChan := make(chan struct{}, 1)
	printChan <- struct{}{}
	word = os.Args[1]
	wg.Add(2)
	go caiyunQuery(word, &wg, printChan)
	go youdaoQuery(word, &wg, printChan)
	wg.Wait()
}