这是我参与「第三届青训营 -后端场」笔记创作活动的的第3篇笔记
三. 基础项目实战
1. 猜数游戏
通过简单的Go语言的基础学习,我们这次来实现一个猜数游戏
猜数游戏的本质就是,通过程序内部随机出一个数字,我们通过输入所猜的数字,判断并返回目标数与所猜数是否相等,如果相等则返回猜中信息,并退出程序,如果不相等则返回目标数与所猜数的大小关系。
首先我们为了实现随机出0~99之间的随机数,我们需要引入"math/rand"包,然后利用rand.Int()函数进行获取一个随机数,代码如下:
import (
"fmt"
"math/rand"
)
func main() {
maxNum := 100
secretNumber := rand.Intn(maxNum)
fmt.Println("当前随机数为: ", secretNumber)
}
然而,我们会发现每次随机出来数都一样,这是因为每次没有调用rand.Seed(xxxx), 导致随机种子都是 1 ,所以如果想要每次随机值不一样,我们就需要用时间戳作为随机种子
因此形成以下代码:
import (
"fmt"
"math/rand"
"time"
)
func main() {
maxNum := 100
rand.Seed(time.Now().UnixNano()) //通过时间戳作为随机种子
secretNumber := rand.Intn(maxNum)
fmt.Println("当前随机数为: ", secretNumber)
}
接下来我们将实现如何读取用户输入的数据,并解析成数字,我们可以添加以下代码就能获取我们输入的数据,并判断与返回是否为数字类型
var guess int
_, err := fmt.Scanf("%d", &guess) //获取输入并判断是否为int类型
if err != nil {
fmt.Println("不是数字类型,请输入数字") //如果不是int类型则输出错误
return
}
接下来我们需要将我们所猜的数字与被猜数进行比较判断,并且返回比较结果
if guess > secretNumber {
fmt.Println("你猜的数字大于被猜数,请再输入一次")
} else if guess < secretNumber {
fmt.Println("你猜的数字小于被猜数,请再输入一次")
} else {
fmt.Println("恭喜你,猜中了这个数字")
}
最后我们希望我们这个程序在我们猜到数字之后再退出,于是我们在我们输入的位置加上一个无限循环的for语句,最后实现整个猜数字流程的代码就实现了
package main
import (
"fmt"
"math/rand"
"time"
)
func main() {
maxNum := 100
rand.Seed(time.Now().UnixNano())
secretNumber := rand.Intn(maxNum)
fmt.Println("请输入你要猜的数字")
for {
var guess int
_, err := fmt.Scanf("%d", &guess)
if err != nil {
fmt.Println("不是数字类型,请输入数字")
continue
}
fmt.Println("You guess is", guess)
if guess > secretNumber {
fmt.Println("你猜的数字大于被猜数,请再输入一次")
} else if guess < secretNumber {
fmt.Println("你猜的数字小于被猜数,请再输入一次")
} else {
fmt.Println("恭喜你,猜中了这个数字")
break //当猜中数字后跳出死循环
}
}
}
2. 在线词典
熟练的掌握了 Go语言的各种包的使用,这次我们来使用第三方API来进行实现在线单词词典翻译功能,在这个项目当中,我们将利用 Go语言发送 HTTP 请求、解析 json 数据过来,并且学习如何使用代码生成来提高开发效率。
为了获取我们所需要的 API,我们需要通过抓包来获取
这次项目我们通过以彩云翻译为例,先打开彩云翻译的网页,然后右键网页选择检查或者按下 F12 来打开开发者工具:
然后我们找到网络一栏并且选择它
然后我们通过执行对 good单词进行翻译,仔细查看网络,找到一个dict的文件,点击预览就会发现 good单词通过API返回的 json数据
由于我们需要发送这个HTTP请求,但是用代码构建又会很麻烦因此我们只需要将dict右键找到复制(Copy),再选择复制为cURL(Copy as cURL),再通过Convert curl commands to code (curlconverter.com)这个网页,将代码粘贴到curl command,就可以获得以下代码(已加入解释注释)
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("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 resp.Body.Close()
//读取相应
bodyText, err := ioutil.ReadAll(resp.Body)
if err != nil {
log.Fatal(err)
}
fmt.Printf("%s\n", bodyText)
}
我们将这一串代码copy到我们的编译器当中即可,然后我们运行这段代码,就会清楚的发现我们是能够发送请求,并且返回了一大串JSON数据
但是我们需要制作一个结构体来承载这个JSON数据的格式,因此我们找到dict文件对其右键,选择复制,复制其响应,然后通过网页JSON转Golang Struct - 在线工具 - OKTools选择嵌套类型并改名为DictResponse,就可以得到我们想要的结构体作为响应结构体。
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"`
}
接下来,我们为了使让我们的输入不再固定,因此我们需要创建一个结构体来代替我们的输入,对比请求代码,我们需要两个数据,一个是翻译类型,一个是被翻译对象。因此我们创建以下结构体,并使用json tag对其进行JSON处理:
type DictRequest struct {
TransType string `json:"trans_type"`
Source string `json:"source"`
}
然后我们通过初始化DictRequest结构体来发送请求数据,最后使用json.Unmarshal进行反序列化对返回的数据储存到DictResponse结构体中,我们就实现了如何发送要翻译的数据,并返回其翻译结果。如果想要获取返回数据的特定输出,我们可以通过打印其结构体的某一部分即可,例如我们想要获取我们翻译过后单词的英式读法,和美式读法,我们可以通过以下代码打印出来即可
fmt.Println(word, "UK:", dictResponse.Dictionary.Prons.En, "US:", dictResponse.Dictionary.Prons.EnUs)
最后我们将其包装成一个函数,并且需要传入一个 string 类型的值,作为被翻译的字符串.最后通过main主函数来进行测试其功能.完整代码如下:
import (
"bytes"
"encoding/json"
"fmt"
"io/ioutil"
"log"
"net/http"
"os"
)
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 resp.Body.Close()
bodyText, err := ioutil.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() {
if len(os.Args) != 2 {
fmt.Fprintf(os.Stderr, `usage: simpleDict WORD
example: simpleDict hello
`)
os.Exit(1)
}
word := os.Args[1]
query(word)
}