GO语言工程实践 | 青训营笔记

187 阅读7分钟

之前曾经写过一篇go语言基础文章,但是尚未完成项目实践,只学习了基础知识。现在参加了第六届青训营,也因此将之前的笔记重新整理,正好是暑假,可以更认真的整理技术框架、学习新知识、增长项目经验。

猜谜游戏

涉及知识点:随机数种子

在Golang中,随机数生成器是基于一个种子(seed)生成的。种子是一个整数值,它用于初始化随机数生成器的状态。如果两个随机数生成器的种子相同,它们就会生成相同的随机数序列。

在这个猜数字游戏的例子中,我们使用了time包中的UnixNano()函数来获取当前时间的纳秒数作为种子,以保证每次运行程序生成的随机数都是不同的。如果我们没有使用种子或者使用了相同的种子,那么每次运行程序生成的随机数序列都会相同,这样就无法保证游戏的随机性和公正性。

具体来说,我们使用了rand包中的Seed()函数来将当前时间的纳秒数作为种子,并将其传递给rand.Intn()函数,以生成一个1到100之间的随机整数。Seed()函数只需要在程序运行时调用一次即可,因为它会将种子保存到随机数生成器的状态中,随后的随机数生成都会基于这个种子。

package main

import (
    "fmt"
    "math/rand"
    "time"
)

func main() {
    // 生成一个1到100之间的随机整数
    rand.Seed(time.Now().UnixNano())
    secretNumber := rand.Intn(100) + 1

    // 控制台输出欢迎信息
    fmt.Println("欢迎来到猜数字游戏!")
    fmt.Println("请猜一个1到100之间的整数。")

    // 循环获取用户输入,直到猜中为止
    var guess int
    for {
        fmt.Print("你的猜测是:")
        fmt.Scan(&guess)
        if guess < secretNumber {
            fmt.Println("太小了!再试一次。")
        } else if guess > secretNumber {
            fmt.Println("太大了!再试一次。")
        } else {
            fmt.Println("恭喜你猜中了!")
            break
        }
    }
}

在线词典

涉及知识点:api调用,http服务,json序列化,解析response body,代码生成

第一步:请求代码生成

我在这里调用了百度翻译的api,使用教程提供的Convert curl to Go (curlconverter.com)进行了代码生成,得到代码如下:

package main

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

func main() {
	client := &http.Client{}
	var data = strings.NewReader(`from=en&to=zh&query=hello&transtype=realtime&simple_means_flag=3&sign=54706.276099&token=c4cd174dca1ef9d313024df75cf74d42&domain=common&ts=1690296997065`)
	req, err := http.NewRequest("POST", "https://fanyi.baidu.com/v2transapi?from=en&to=zh", data)
	if err != nil {
		log.Fatal(err)
	}
	req.Header.Set("Accept", "*/*")
	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("Acs-Token", "1690296988794_1690296997094_/oJqs0ycj8r8vPlZquYwo9HOqn/dnoyTnUz3MwAbF9Tb1QJd/DNzadYqVZMA9mLn9kqyLBVAOdUEBkhyIXDkfYdJHbPYkb/0A7UfQhSR4F4ZFMmvsb6NURwEMgV8C2wwJDkvBuzNs/2KzhOVLFFyXsx61aSGO3DOF8ayUoBTY8ugp9PDe8pCbnWoaQwEoRLnBTtCnZskVGzbCCRvK93pko5BnIgVeLAQpUL4MDXA1mmvcVbmexlPMMlCewWL5pmw2sP2VIj1oI9YFrUs6TlivN17IJgWyL3tjd+GoO1UTAlB2LItuSBRyO4eRpoQov6dVuZ8LAIQP9iJi8u/xtMXmDO6/qyvW4GxbMK6VA/mb3ZBFPyo5NWomd9eEFVVpB9hsUs6qyYkVKH220znwfn/7wf96gokvTWAo0YZKJ767jp43DKDdYH3aqvi09Uild4ftUTNXU66cYqA7744E2IJrQS+NEQM9oonotrDFf0hjp13Nss0Tiagxrg1Wp8O05tj3HLCYTijBjnB5/coyGvULw==")
	req.Header.Set("Connection", "keep-alive")
	req.Header.Set("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8")
	req.Header.Set("Cookie", "BIDUPSID=E54970232927D08BF091EB133681C737; PSTM=1683706717; BAIDUID=E54970232927D08B468F87308B610090:FG=1; BAIDUID_BFESS=E54970232927D08B468F87308B610090:FG=1; REALTIME_TRANS_SWITCH=1; FANYI_WORD_SWITCH=1; HISTORY_SWITCH=1; SOUND_SPD_SWITCH=1; SOUND_PREFER_SWITCH=1; H_PS_PSSID=26350; ab_sr=1.0.1_MzJiMDg1ZGJhNDZlNWRkMzZlNGM1N2FlZGEyOWEwZGRhMjU1NzA1NWI3YmFmMDBlNGJiY2I1ZTU5OWMyOWNhNzkyY2Q3NWE0ZTg0YTdlMTcxYzllZDU1ZTAyM2Y4ZWU2MDMyZjE5NjY4MDgxYjM0ODNiZmFlZDk0MTQzNmNmNmY3MjcxMTJlMTI1MjE1NzkzYzA1NjkyMmRiZWZhNWE0OQ==")
	req.Header.Set("Origin", "https://fanyi.baidu.com")
	req.Header.Set("Referer", "https://fanyi.baidu.com/?aldtype=16047")
	req.Header.Set("Sec-Fetch-Dest", "empty")
	req.Header.Set("Sec-Fetch-Mode", "cors")
	req.Header.Set("Sec-Fetch-Site", "same-origin")
	req.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/115.0.0.0 Safari/537.36 Edg/115.0.1901.183")
	req.Header.Set("X-Requested-With", "XMLHttpRequest")
	req.Header.Set("sec-ch-ua", `"Not/A)Brand";v="99", "Microsoft Edge";v="115", "Chromium";v="115"`)
	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 := io.ReadAll(resp.Body)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("%s\n", bodyText)
}

得到了JSON:

第二步:基础调用逻辑

搭建一个基础的服务器用于作为中介

package main

import (
    "fmt"
    "net/http"
    "log"
    "encoding/json"
)

type Definition struct {
    Definition string `json:"definition"`
}

func main() {
    http.HandleFunc("/", handleIndex)
    http.HandleFunc("/define", handleDefine)
    fmt.Println("Listening on :3000")
    http.ListenAndServe(":3000", nil)
}

func handleIndex(w http.ResponseWriter, r *http.Request) {
    fmt.Fprint(w, "Welcome to the online dictionary!")
}

func handleDefine(w http.ResponseWriter, r *http.Request) {
    word := r.URL.Query().Get("word")
    if word == "" {
        http.Error(w, "Please provide a word to define", http.StatusBadRequest)
        return
    }
    resp, err := http.Get("https://api.dictionaryapi.dev/api/v2/entries/en/" + word)
    if err != nil {
        http.Error(w, "Failed to retrieve definition", http.StatusInternalServerError)
        return
    }
    defer resp.Body.Close()

    var definitions []Definition
    err = json.NewDecoder(resp.Body).Decode(&definitions)
    if err != nil {
        http.Error(w, "Failed to decode definition", http.StatusInternalServerError)
        return
    }

    if len(definitions) == 0 {
        fmt.Fprintf(w, "No definition found for %s", word)
        return
    }

    fmt.Fprintf(w, "%s: %s", word, definitions[0].Definition)
}

第三步:完善以及完成代码

由于百度云api对开发者要求比较严格,我的代码中的token与sign部分只是从浏览器截取,无法完成比较完善的功能,以下代码仅供参考

package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"log"
	"net/http"
	"time"
)

type DictRequest struct {
	From            string `url:"from"`
	To              string `url:"to"`
	Query           string `url:"query"`
	TransType       string `url:"transtype"`
	SimpleMeansFlag int    `url:"simple_means_flag"`
	Sign            string `url:"sign"`
	Token           string `url:"token"`
	Domain          string `url:"domain"`
	Timestamp       int64  `url:"ts"`
}

type DictResponse struct {
	TransResult struct {
		Data []struct {
			Dst string `json:"dst"`
			Src string `json:"src"`
		} `json:"data"`
		From     string `json:"from"`
		To       string `json:"to"`
		Status   int    `json:"status"`
		Type     int    `json:"type"`
		Phonetic []struct {
			SrcStr string `json:"src_str"`
			TrgStr string `json:"trg_str"`
		} `json:"phonetic"`
	} `json:"trans_result"`
	DictResult struct {
		Edict struct {
			Item []struct {
				TrGroup []struct {
					Tr          []string `json:"tr"`
					Example     []string `json:"example"`
					SimilarWord []string `json:"similar_word"`
				} `json:"tr_group"`
				Pos string `json:"pos"`
			} `json:"item"`
			Word string `json:"word"`
		} `json:"edict"`
		From        string `json:"from"`
		SimpleMeans struct {
			WordName  string   `json:"word_name"`
			From      string   `json:"from"`
			WordMeans []string `json:"word_means"`
			Tags      struct {
				Core  []string `json:"core"`
				Other []string `json:"other"`
			} `json:"tags"`
			Exchange struct {
				WordPl []string `json:"word_pl"`
			} `json:"exchange"`
			Symbols []struct {
				PhEn  string `json:"ph_en"`
				PhAm  string `json:"ph_am"`
				Parts []struct {
					Part  string   `json:"part"`
					Means []string `json:"means"`
				} `json:"parts"`
				PhOther string `json:"ph_other"`
			} `json:"symbols"`
		} `json:"simple_means"`
		Common struct {
			Text string `json:"text"`
		} `json:"common"`
		Collins struct {
			Entry []struct {
				Type    string `json:"type"`
				EntryID string `json:"entry_id"`
				Value   []struct {
					MeanType []struct {
						InfoType string `json:"info_type"`
						InfoID   string `json:"info_id"`
						Example  []struct {
							ExampleID string `json:"example_id"`
							TtsSize   string `json:"tts_size"`
							Tran      string `json:"tran"`
							Ex        string `json:"ex"`
							TtsMp3    string `json:"tts_mp3"`
						} `json:"example,omitempty"`
						Posc []struct {
							Tran    string `json:"tran"`
							PoscID  string `json:"posc_id"`
							Example []struct {
								ExampleID string `json:"example_id"`
								Tran      string `json:"tran"`
								Ex        string `json:"ex"`
								TtsMp3    string `json:"tts_mp3"`
							} `json:"example"`
							Def string `json:"def"`
						} `json:"posc,omitempty"`
					} `json:"mean_type"`
					Gramarinfo []struct {
						Tran  string `json:"tran"`
						Type  string `json:"type"`
						Label string `json:"label"`
					} `json:"gramarinfo"`
					Tran   string `json:"tran"`
					Def    string `json:"def"`
					MeanID string `json:"mean_id"`
					Posp   []struct {
						Label string `json:"label"`
					} `json:"posp"`
				} `json:"value"`
			} `json:"entry"`
			WordName      string `json:"word_name"`
			WordID        string `json:"word_id"`
			WordEmphasize string `json:"word_emphasize"`
			Frequence     string `json:"frequence"`
		} `json:"collins"`
		Lang   string `json:"lang"`
		Oxford struct {
			Entry []struct {
				Tag  string `json:"tag"`
				Name string `json:"name"`
				Data []struct {
					Tag  string `json:"tag"`
					Data []struct {
						Tag  string `json:"tag"`
						Data []struct {
							Tag  string `json:"tag"`
							Data []struct {
								Tag  string `json:"tag"`
								Data []struct {
									Tag    string `json:"tag"`
									EnText string `json:"enText,omitempty"`
									ChText string `json:"chText,omitempty"`
									G      string `json:"g,omitempty"`
									Data   []struct {
										Text      string `json:"text"`
										HoverText string `json:"hoverText"`
									} `json:"data,omitempty"`
								} `json:"data"`
							} `json:"data"`
						} `json:"data,omitempty"`
						P     string `json:"p,omitempty"`
						PText string `json:"p_text,omitempty"`
						N     string `json:"n,omitempty"`
						Xt    string `json:"xt,omitempty"`
					} `json:"data"`
				} `json:"data"`
			} `json:"entry"`
			Unbox []struct {
				Tag  string `json:"tag"`
				Type string `json:"type"`
				Name string `json:"name"`
				Data []struct {
					Tag     string `json:"tag"`
					Text    string `json:"text,omitempty"`
					Words   string `json:"words,omitempty"`
					Outdent string `json:"outdent,omitempty"`
					Data    []struct {
						Tag    string `json:"tag"`
						EnText string `json:"enText"`
						ChText string `json:"chText"`
					} `json:"data,omitempty"`
				} `json:"data"`
			} `json:"unbox"`
		} `json:"oxford"`
		BaiduPhrase []struct {
			Tit   []string `json:"tit"`
			Trans []string `json:"trans"`
		} `json:"baidu_phrase"`
		Sanyms []struct {
			Tit  string `json:"tit"`
			Type string `json:"type"`
			Data []struct {
				P string   `json:"p"`
				D []string `json:"d"`
			} `json:"data"`
		} `json:"sanyms"`
		QueryExplainVideo struct {
			ID           int    `json:"id"`
			UserID       string `json:"user_id"`
			UserName     string `json:"user_name"`
			UserPic      string `json:"user_pic"`
			Query        string `json:"query"`
			Direction    string `json:"direction"`
			Type         string `json:"type"`
			Tag          string `json:"tag"`
			Detail       string `json:"detail"`
			Status       string `json:"status"`
			SearchType   string `json:"search_type"`
			FeedURL      string `json:"feed_url"`
			Likes        string `json:"likes"`
			Plays        string `json:"plays"`
			CreatedAt    string `json:"created_at"`
			UpdatedAt    string `json:"updated_at"`
			DuplicateID  string `json:"duplicate_id"`
			RejectReason string `json:"reject_reason"`
			CoverURL     string `json:"coverUrl"`
			VideoURL     string `json:"videoUrl"`
			ThumbURL     string `json:"thumbUrl"`
			VideoTime    string `json:"videoTime"`
			VideoType    string `json:"videoType"`
		} `json:"queryExplainVideo"`
	} `json:"dict_result"`
	LijuResult struct {
		Double string   `json:"double"`
		Tag    []string `json:"tag"`
		Single string   `json:"single"`
	} `json:"liju_result"`
	Logid int64 `json:"logid"`
}

func main() {
	client := &http.Client{}
	request := DictRequest{
		From:            "en",
		To:              "zh",
		Query:           "hello",
		TransType:       "trans",
		SimpleMeansFlag: 3,
		Sign:            "54706.276099",
		Token:           "c4cd174dca1ef9d313024df75cf74d42",
		Domain:          "common",
		Timestamp:       time.Now().Unix(),
	}
	buf, err := json.Marshal(request)
	if err != nil {
		log.Fatal(err)
	}
	var data = bytes.NewReader(buf)
	req, err := http.NewRequest("POST", "https://fanyi.baidu.com/v2transapi?from=en&to=zh", data)
	if err != nil {
		log.Fatal(err)
	}
	req.Header.Set("Accept", "*/*")
	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("Acs-Token", "1690296988794_1690296997094_/oJqs0ycj8r8vPlZquYwo9HOqn/dnoyTnUz3MwAbF9Tb1QJd/DNzadYqVZMA9mLn9kqyLBVAOdUEBkhyIXDkfYdJHbPYkb/0A7UfQhSR4F4ZFMmvsb6NURwEMgV8C2wwJDkvBuzNs/2KzhOVLFFyXsx61aSGO3DOF8ayUoBTY8ugp9PDe8pCbnWoaQwEoRLnBTtCnZskVGzbCCRvK93pko5BnIgVeLAQpUL4MDXA1mmvcVbmexlPMMlCewWL5pmw2sP2VIj1oI9YFrUs6TlivN17IJgWyL3tjd+GoO1UTAlB2LItuSBRyO4eRpoQov6dVuZ8LAIQP9iJi8u/xtMXmDO6/qyvW4GxbMK6VA/mb3ZBFPyo5NWomd9eEFVVpB9hsUs6qyYkVKH220znwfn/7wf96gokvTWAo0YZKJ767jp43DKDdYH3aqvi09Uild4ftUTNXU66cYqA7744E2IJrQS+NEQM9oonotrDFf0hjp13Nss0Tiagxrg1Wp8O05tj3HLCYTijBjnB5/coyGvULw==")
	req.Header.Set("Connection", "keep-alive")
	req.Header.Set("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8")
	req.Header.Set("Cookie", "BIDUPSID=E54970232927D08BF091EB133681C737; PSTM=1683706717; BAIDUID=E54970232927D08B468F87308B610090:FG=1; BAIDUID_BFESS=E54970232927D08B468F87308B610090:FG=1; REALTIME_TRANS_SWITCH=1; FANYI_WORD_SWITCH=1; HISTORY_SWITCH=1; SOUND_SPD_SWITCH=1; SOUND_PREFER_SWITCH=1; H_PS_PSSID=26350; ab_sr=1.0.1_MzJiMDg1ZGJhNDZlNWRkMzZlNGM1N2FlZGEyOWEwZGRhMjU1NzA1NWI3YmFmMDBlNGJiY2I1ZTU5OWMyOWNhNzkyY2Q3NWE0ZTg0YTdlMTcxYzllZDU1ZTAyM2Y4ZWU2MDMyZjE5NjY4MDgxYjM0ODNiZmFlZDk0MTQzNmNmNmY3MjcxMTJlMTI1MjE1NzkzYzA1NjkyMmRiZWZhNWE0OQ==")
	req.Header.Set("Origin", "https://fanyi.baidu.com")
	req.Header.Set("Referer", "https://fanyi.baidu.com/?aldtype=16047")
	req.Header.Set("Sec-Fetch-Dest", "empty")
	req.Header.Set("Sec-Fetch-Mode", "cors")
	req.Header.Set("Sec-Fetch-Site", "same-origin")
	req.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/115.0.0.0 Safari/537.36 Edg/115.0.1901.183")
	req.Header.Set("X-Requested-With", "XMLHttpRequest")
	req.Header.Set("sec-ch-ua", `"Not/A)Brand";v="99", "Microsoft Edge";v="115", "Chromium";v="115"`)
	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 := io.ReadAll(resp.Body)
	if err != nil {
		log.Fatal(err)
	}
	var dictResponse DictResponse
	err = json.Unmarshal(bodyText, &dictResponse)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Print("%#v\n", dictResponse)
}