GO语言工程实践课后作业 | 青训营

76 阅读5分钟

这篇文章主要是对go语言实践课的课后作业的详解

1.猜谜游戏

猜数字游戏也是学习编程语言的一个经典项目,透过这个小程序,我们可以掌握go语言中的输入输出、条件语句以及随机数生成的应用。

生成随机数:

在Go语言中,通过使用标准库中的math/rand包,我们可以实现随机数的生成。

package main

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

func main() {
	// 设置随机种子,以确保每次运行生成不同的随机数序列
	rand.Seed(time.Now().UnixNano())

	// 生成一个 [0, n) 的随机整数
	n := 10
	randomNumber := rand.Intn(n)

	fmt.Printf("随机生成的数字: %d\n", randomNumber)
}

请注意,为了确保每次运行都能生成不同的随机数序列,我们使用了time.Now().UnixNano()作为种子来初始化随机数生成器。这有助于保证每次运行程序时都会得到不同的随机数。

程序中随机数的代码

  maxnum := 100
	rand.Seed(time.Now().UnixNano())
	randownum := rand.Intn(maxnum)
	fmt.Println(randownum)

通常,用时间戳来作为随机数的种子。(这一点特性和C语言的rand()是类似的。)

接着是让用户自行输入

fmt.Println("请输入你的数字")
reader := bufio.NewReader(os.Stdin)
input, err := reader.ReadString('\n')
if err != nil {
        fmt.Println("输入有误")
        return
}

input = strings.TrimSuffix(input, "\r\n"

reader := bufio.NewReader(os.Stdin):这一行代码在Go语言中创建了一个新的bufio.Reader对象,它会从标准输入(os.Stdin)中读取数据。bufio.Reader用于从指定的输入源中进行读取操作,这里我们使用它来从控制台读取用户的输入。

input, err := reader.ReadString('\n'):这行代码从标准输入中读取数据,直到遇到换行符 '\n' 为止。它将读取的数据存储在input变量中,并在读取过程中检查是否发生了错误。如果在读取数据时出现了错误,比如输入流结束或无法读取数据,错误信息将被存储在err变量中。

strings.TrimSuffix() 函数:这一行代码使用strings.TrimSuffix()函数来移除input变量中可能存在的结尾换行符 '\n'。通常情况下,用户的输入以换行符结尾,使用这个函数可以将换行符去除,从而得到更规范的输入。

guess, err := strconv.Atoi(input):这一行代码尝试将经过修剪的input字符串转换为整数类型。它使用strconv.Atoi()函数来进行转换。如果转换成功,转换后的结果会存储在guess变量中;如果转换失败,错误信息将存储在err变量中。这里假设用户的输入是一个表示整数的字符串。如果用户输入的不是合法的整数字符串,转换将会失败并产生错误。

最后加上循环和判断语句即可

for {
		guess, err := strconv.Atoi(input)
		if err != nil {
		fmt.Println("test")
			fmt.Println("再试一次")
			return
		}
		fmt.Printf("%T%d", guess, guess)

		if count > 5 {
			fmt.Println("次数已超过")
			return
		} else if guess == randownum {
			fmt.Println("恭喜你通过了")
			return
		} else if guess < randownum {
			fmt.Println("你输入的太小了")
		} else {
			fmt.Println("你输入的太大了")
		}
		count++
	}

二、在线词典

第二个案例是一个命令行词典。效果是输入一个单词,命令行中会显示这个单词的发音和注释。

课上主要是对彩云小译网页版进行抓包分析,,使用go发送http请求编写一个翻译小工具。

主要实现:

  • 翻译
  • 单词字典查询

一、抓包

打开网页按F12调出开发人员工具,再切换到网络选项卡,在输入框里输入内容开始抓包,会抓到个接口,dict为查询字典的接口。

image.png 然后分析这个请求

image.png 发现能够直接英译中

二、自动编写代码

下面用其他简单的方法去直接编译json代码,先吧url复制下来,待会有用

image.png

点击 Copy as cURL(bash) 后,打开这个网址:curlconverter.com/go/ 把刚才复制的东西粘贴进去,自动会生成相应的请求代码:

package main

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

func main() {
	client := &http.Client{}
	var data = strings.NewReader(`{"trans_type":"en2zh","source":"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,ar;q=0.8")
	req.Header.Set("app-name", "xy")
	req.Header.Set("content-type", "application/json;charset=UTF-8")
	req.Header.Set("device-id", "990faa53baf70befe77f49b01b2daad7")
	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("sec-ch-ua", `"Chromium";v="116", "Not)A;Brand";v="24", "Google Chrome";v="116"`)
	req.Header.Set("sec-ch-ua-mobile", "?0")
	req.Header.Set("sec-ch-ua-platform", `"Windows"`)
	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/116.0.0.0 Safari/537.36")
	req.Header.Set("x-authorization", "token:qgemv4jr1y38jyq6vhvi")
	req.Header.Set("x-forwarded-for", "1.1.1.1")
	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)
}

复制去vscode中直接运行代码

image.png 说明请求成功

接下来需要构造一个结构体,让这个结构体的字段名称和JSON的结构一一对应

三、解析 response body

完成了请求的序列化后,我们还要进行相应的反序列化,这样才能得到结果.

打开这个工具网站:oktools.net/json2go

然后,把彩云小译界面的 response 的json粘贴进去:

image.png 可以通过嵌套把结构体整合出来然后替换到原来的代码中去

最后把代码整理一下最终代码如下

package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "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 {
    } `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 main() {
    if len(os.Args) != 2 {
       fmt.Fprintf(os.Stderr, `usage: simpleDict WORD example: simpleDict hello`)
       os.Exit(1)
    }
    word := os.Args[1]
    late(word)
}

func late(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("authority", "api.interpreter.caiyunai.com")
    req.Header.Set("accept", "application/json, text/plain, */*")
    req.Header.Set("accept-language", "zh-CN,zh;q=0.9")
    req.Header.Set("app-name", "xy")
    req.Header.Set("cache-control", "no-cache")
    req.Header.Set("content-type", "application/json;charset=UTF-8")
    req.Header.Set("device-id", "b72e9f6cbb97432941b8adf317a17dee")
    req.Header.Set("origin", "https://fanyi.caiyunapp.com")
    req.Header.Set("os-type", "web")
    req.Header.Set("os-version", "")
    req.Header.Set("pragma", "no-cache")
    req.Header.Set("referer", "https://fanyi.caiyunapp.com/")
    req.Header.Set("sec-ch-ua", `"Not/A)Brand";v="99", "Google Chrome";v="115", "Chromium";v="115"`)
    req.Header.Set("sec-ch-ua-mobile", "?0")
    req.Header.Set("sec-ch-ua-platform", `"Windows"`)
    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/115.0.0.0 Safari/537.36")
    req.Header.Set("x-authorization", "token:qgemv4jr1y38jyq6vhvi")
    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)
    }

    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("%#v\n", dictResponse)
    fmt.Println(word, "UK:", dictResponse.Dictionary.Prons.En,
       "US:", dictResponse.Dictionary.Prons.EnUs)
    for _, item := range dictResponse.Dictionary.Explanations {
       fmt.Println(item)
    }
}

在命令行运行:输入要翻译的单词,可以调用接口实现在线翻译 image.png