这是我参与「第五届青训营」伴学笔记创作活动的第1天
猜谜游戏
1.1猜谜游戏 - 生成随机数
math/rand 是 Go 语言中的随机数生成包。它提供了生成随机数、随机种子等功能。
- 使用
rand.Intn(n)可以生成一个 [0,n) 的随机整数。- 使用
rand.Float64()可以生成一个 [0.0,1.0) 的随机浮点数。- 使用
rand.Seed(seed)可以设置随机种子,seed 为int64类型。需要注意的是,math/rand 库默认使用的是线性同余随机数生成器,如果需要高质量的随机数,可以考虑使用其他库如 crypto/rand。
time.Now().UnixNano()是获取当前时间的 Unix 时间戳(以纳秒为单位)。因为时间戳是不断变化的,所以使用当前时间戳作为随机种子能够保证生成的随机数序列是不同的
package main
import (
"fmt"
"math/rand"
)
func main() {
max := 100 //定义我们随机数的范围
secretNumber := rand.Intn(max) //生成这个范围的随机数
fmt.Println("你的随机数字是:", secretNumber) //输出随机数字
}
//如果你一直打印的话,就会发现打印出来的都是81,同一个数字?因为我们没有设置随机数种子
//在使用 math/rand 库生成随机数之前,需要先设置随机种子。随机种子是一个数字,用于初始化随机数生成器。相同的随机种子会生成相同的随机数序列
复制代码
//设置随机数种子,将其设置为当前时间戳
rand.Seed(time.Now().UnixNano())
复制代码
//完整代码
package main
import (
"fmt"
"math/rand"
"time"
)
func main() {
max := 100 //定义我们随机数的范围
rand.Seed(time.Now().UnixNano())
secretNumber := rand.Intn(max) //生成这个范围的随机数
fmt.Println("你的随机数字是:", secretNumber) //输出随机数字
}
复制代码
1.2猜谜游戏 - 读取用户输入
bufio包提供了带缓存的 I/O 接口,其中包括bufio.NewReader函数,可以用来创建一个带缓存的读取器。
strings包中的Trim函数可以用于将字符串首尾的指定字符去掉,在这里传入的第二个参数是"\r\n",表示将字符串首尾的回车和换行符去掉。在 Windows 下,行结尾为
\r\n,而在 Linux 和 macOS 下,行结尾为\n,因此通过使用这个函数可以在不同的操作系统下都能将行末的回车和换行符去掉
strings.Trim函数只会去掉首尾的字符,并不会去掉字符串中间的字符。如果需要去掉字符串中间的字符,可以使用strings.Replace或strings.ReplaceAll函数
package main
import (
"bufio"
"fmt"
"math/rand"
"os"
"strconv"
"strings"
"time"
)
func main() {
maxNum := 100
rand.Seed(time.Now().UnixNano())
secretNumber := rand.Intn(maxNum)
fmt.Println("The secret number is ", secretNumber)
//----------------------------------------------从这里开始是读取用户输入的部分
fmt.Println("Please input your guess")//给用户提示这是猜数字游戏
//os.Stdin是一个 io.Reader 接口,表示标准输入。传入 os.Stdin 可以创建一个读取标准输入的带缓存读取器
reader := bufio.NewReader(os.Stdin)//创建一个带缓存的读取器
input, err := reader.ReadString('\n')//读取一行输出(读取输出直到遇到换行符为止)
//复习一下这个错误检查用法:当一个函数调用返回了一个错误值时,通常会将该错误值用作返回值中的最后一个参数。在这种情况下,如果函数调用成功,那么错误值为 nil,如果调用失败,那么错误值不为 nil
if err != nil {
fmt.Println("An error occured while reading input. Please try again", err)//错误信息
return//打印错误然后返回
}
input = strings.Trim(input, "\r\n")//去掉换行符:将字符串首尾的 \r 和 \n 去掉
guess, err := strconv.Atoi(input)//转化为数字
if err != nil {//判断错误信息
fmt.Println("Invalid input. Please enter an integer value")
return
}
fmt.Println("You guess is", guess)//输出用户猜测的数字
//------------------------------------------------------
}
复制代码
1.3猜谜游戏 - 读取用户输入
if判断语句,那就没什么好讲的了
package main
import (
"bufio"
"fmt"
"math/rand"
"os"
"strconv"
"strings"
"time"
)
func main() {
maxNum := 100//获取随机数范围
rand.Seed(time.Now().UnixNano())//设置随机数种子,防止出现每次数字都是一样的问题
secretNumber := rand.Intn(maxNum)//设置随机数
fmt.Println("The secret number is ", secretNumber)//输出当前随机数的数值
//--------------------------------------------------(简易版本)
fmt.Println("Please input your guess")//提示用户输入猜测的数字
reader := bufio.NewReader(os.Stdin)//创建一个带缓存的读取
input, err := reader.ReadString('\n')//读取一行信息(在这里是遇到 \n 就结束读取)
if err != nil {//判断是否有错误信息,err不为 nil 证明函数调用失败
fmt.Println("An error occured while reading input. Please try again", err)
return
}
input = strings.Trim(input, "\r\n")//去掉换行符:将字符串首尾的 \r 和 \n 去掉
guess, err := strconv.Atoi(input)//字符串转化为数字
if err != nil {//判断函数调用是否成功
fmt.Println("Invalid input. Please enter an integer value")
return
}
fmt.Println("You guess is", guess)//输出用户猜测的数字
if guess > secretNumber {//if系列判断用户猜测的数字是过大还是过小,如果都不是就返回你猜对了的结果
fmt.Println("Your guess is bigger than the secret number. Please try again")
} else if guess < secretNumber {
fmt.Println("Your guess is smaller than the secret number. Please try again")
} else {
fmt.Println("欧尼酱你猜对啦!")
}
//----------------------------------------------------------------------
}
复制代码
1.4猜谜游戏 - 实现判断逻辑
if判断逻辑,跟其他语言一样的东西,但仍然要记得这是不加()的,虽然编辑器会提示就是了
if guess > secretNumber {//if系列判断用户猜测的数字是过大还是过小,如果都不是就返回你猜对了的结果
fmt.Println("Your guess is bigger than the secret number. Please try again")
} else if guess < secretNumber {
fmt.Println("Your guess is smaller than the secret number. Please try again")
} else {
fmt.Println("你猜对啦!")
}
复制代码
1.4猜谜游戏 - 实现游戏循环
以上的方式我们只能输入一次数字就结束了,如果数字没有输入正确,也没办法继续猜测,而是只能重新运行开始,那接下来我们就来实现这个功能,加上个for循环
package main
import (
"bufio"
"fmt"
"math/rand"
"os"
"strconv"
"strings"
"time"
)
func main() {
maxNum := 100
rand.Seed(time.Now().UnixNano())
secretNumber := rand.Intn(maxNum)
// fmt.Println("The secret number is ", secretNumber),这行需要注释掉,不然当用户输入第一个不管正确错误,我们当前正确的答案都会暴露出来,那用户就没有游戏体验了
fmt.Println("Please input your guess")
reader := bufio.NewReader(os.Stdin)
for {//将我们的所有内容都融合到循环里面了
input, err := reader.ReadString('\n')//补充内容:去掉前后空格是因为你不知道用户会不会加上前后空格(然后她自己也不知道加没加)
if err != nil {
fmt.Println("An error occured while reading input. Please try again", err)
continue//置换掉了break,我们如果继续使用break会终止for循环的,而我们只需要跳过当次就行了
}
input = strings.Trim(input, "\r\n")
guess, err := strconv.Atoi(input)
if err != nil {
fmt.Println("Invalid input. Please enter an integer value")
continue
}
fmt.Println("You guess is", guess)
if guess > secretNumber {
fmt.Println("Your guess is bigger than the secret number. Please try again")
} else if guess < secretNumber {
fmt.Println("Your guess is smaller than the secret number. Please try again")
} else {
fmt.Println("Correct, you Legend!")
break
}
}
}
复制代码
在线词典
2.1在线词典 - 抓包
//得到我们的JSON,这里替换了查词的意思,换成了good这个单词
curl 'https://api.interpreter.caiyunai.com/v1/dict' \
-H 'authority: api.interpreter.caiyunai.com' \
-H 'accept: application/json, text/plain, */*' \
-H 'accept-language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6' \
-H 'app-name: xy' \
-H 'content-type: application/json;charset=UTF-8' \
-H 'device-id;' \
-H 'origin: https://fanyi.caiyunapp.com' \
-H 'os-type: web' \
-H 'os-version;' \
-H 'referer: https://fanyi.caiyunapp.com/' \
-H 'sec-ch-ua: "Not_A Brand";v="99", "Microsoft Edge";v="109", "Chromium";v="109"' \
-H 'sec-ch-ua-mobile: ?0' \
-H 'sec-ch-ua-platform: "Windows"' \
-H 'sec-fetch-dest: empty' \
-H 'sec-fetch-mode: cors' \
-H 'sec-fetch-site: cross-site' \
-H 'user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36 Edg/109.0.1518.52' \
-H 'x-authorization: token:qgemv4jr1y38jyq6vhvi' \
--data-raw '{"trans_type":"en2zh","source":"good"}' \
--compressed
复制代码
2.2在线词典 - 代码生成
- 这个时候需要打开一个网址将其转化成代码
- 代码生成网址
client.Do(req)是Go语言中net/http包中的函数,用于发送HTTP请求。它接受一个http.Request类型的请求对象作为参数
//生成代码
package main
import (
"fmt"
"io/ioutil"
"log"
"net/http"
"strings"
)
func main() {
client := &http.Client{}
//创建一个新的HTTP请求
//"https://api.interpreter.caiyunai.com/v1/dict" 是请求的URL
//data是请求体, 它被用来作为请求发送时的Body
var data = strings.NewReader(`{"trans_type":"en2zh","source":"good"}`)
//返回两个值,第一个值是一个http.Request类型的请求对象,第二个值是一个错误对象。它们被赋值给req和err变量
req, err := http.NewRequest("POST", "https://api.interpreter.caiyunai.com/v1/dict", data)
if err != nil {//请求创建成功,那么err的值为nil, 反之则不是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,en;q=0.8,en-GB;q=0.7,en-US;q=0.6")
req.Header.Set("app-name", "xy")
req.Header.Set("content-type", "application/json;charset=UTF-8")
req.Header.Set("device-id", "")
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", `"Not_A Brand";v="99", "Microsoft Edge";v="109", "Chromium";v="109"`)
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/109.0.0.0 Safari/537.36 Edg/109.0.1518.52")
req.Header.Set("x-authorization", "token:qgemv4jr1y38jyq6vhvi")
//发起请求
//client是一个http.Client对象, req是一个http.Request对象
resp, err := client.Do(req)//函数返回两个值,第一个值是一个http.Response类型的响应对象,第二个值是一个错误对象。它们被赋值给resp和err变量
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)//输出内容格式化为字符串类型
}
复制代码
生成的JSON结果进行格式化
{
"rc": 0,
"wiki": {
"known_in_laguages": 63,
"description": {
"source": "tangible and intangible thing, except labor tied services, that satisfies human wants and provides utility",
"target": null
},
"id": "Q28877",
"item": {
"source": "good",
"target": "\u5546\u54c1"
},
"image_url": "http://www.caiyunapp.com/imgs/link_default_img.png",
"is_subject": "true",
"sitelink": "https://www.caiyunapp.com/read_mode/?id=6354777915466339550246c5"
},
"dictionary": {
"prons": {
"en-us": "[g\u028ad]",
"en": "[gud]"
},
"explanations": ["a.\u597d\u7684;\u5584\u826f\u7684;\u5feb\u4e50\u7684;\u771f\u6b63\u7684;\u5bbd\u5927\u7684;\u6709\u76ca\u7684;\u8001\u7ec3\u7684;\u5e78\u798f\u7684;\u5fe0\u5b9e\u7684;\u4f18\u79c0\u7684;\u5b8c\u6574\u7684;\u5f7b\u5e95\u7684;\u4e30\u5bcc\u7684", "n.\u5229\u76ca;\u597d\u5904;\u5584\u826f;\u597d\u4eba", "ad.=well"],
"synonym": ["excellent", "fine", "nice", "splendid", "proper"],
"antonym": ["bad", "wrong", "evil", "harmful", "poor"],
"wqx_example": [
["to the good", "\u6709\u5229,\u6709\u597d\u5904"],
["good, bad and indifferent", "\u597d\u7684,\u574f\u7684\u548c\u4e00\u822c\u7684"],
["good innings", "\u957f\u5bff"],
["good and ...", "\u5f88,\u9887;\u5b8c\u5168,\u5f7b\u5e95"],
["do somebody's heart good", "\u5bf9\u67d0\u4eba\u7684\u5fc3\u810f\u6709\u76ca,\u4f7f\u67d0\u4eba\u611f\u5230\u6109\u5feb"],
["do somebody good", "\u5bf9\u67d0\u4eba\u6709\u76ca"],
["be good for", "\u5bf9\u2026\u6709\u6548,\u9002\u5408,\u80dc\u4efb"],
["be good at", "\u5728\u2026\u65b9\u9762(\u5b66\u5f97,\u505a\u5f97)\u597d;\u5584\u4e8e"],
["as good as one's word", "\u4fe1\u5b88\u8bfa\u8a00,\u503c\u5f97\u4fe1\u8d56"],
["as good as", "\u5b9e\u9645\u4e0a,\u51e0\u4e4e\u7b49\u4e8e"],
["all well and good", "\u4e5f\u597d,\u8fd8\u597d,\u5f88\u4e0d\u9519"],
["a good", "\u76f8\u5f53,\u8db3\u8db3"],
["He is good at figures . ", "\u4ed6\u5584\u4e8e\u8ba1\u7b97\u3002"]
],
"entry": "good",
"type": "word",
"related": [],
"source": "wenquxing"
}
}
复制代码
2.3在线词典 - 生成 request body
ioutil.ReadAll 是 Go标准库中 ioutil 包中的一个函数,这个函数接收一个io.Reader类型的参数,并读取这个io.Reader中的全部数据
package main
import (
"bytes"
"encoding/json"
"fmt"
"io/ioutil"
"log"
"net/http"
)
//调用结构体
type DictRequest struct {
//后面跟着的 json:"trans_type", json:"source", json:"user_id" 是结构体字段标签,它们被用来指定字段在json序列化时的名称
TransType string `json:"trans_type"`
Source string `json:"source"`
UserID string `json:"user_id"`
}
func main() {
client := &http.Client{}
request := DictRequest{TransType: "en2zh", Source: "good"}
buf, err := json.Marshal(request)
if err != nil {
log.Fatal(err)
}
//创建一个新的io.Reader类型的变量data, 并将buf这个字节数组作为参数传入bytes.NewReader()函数, 以此来创建一个新的io.Reader对象。这个io.Reader对象可以读取buf中的数据,并将读取到的数据赋值给data
var data = bytes.NewReader(buf)//现在返回的是byte数组而不是字符串
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)
}
//作用:当前函数执行结束时,自动关闭resp.Body这个io.ReadCloser接口类型的对象
defer resp.Body.Close()//调用resp.Body.Close()函数的执行延迟到当前函数执行结束后
//ReadAll函数返回两个值,一个是读取的字节数组,赋值给bodyText,另一个是error类型的错误值
bodyText, err := ioutil.ReadAll(resp.Body)//读取数据
if err != nil {
log.Fatal(err)
}
fmt.Printf("%s\n", bodyText)
}
复制代码
2.4在线词典 - 解析 response body
在线工具 - OKTools = > 点击JSON转Go的那个,选择
转换-嵌套
type AutoGenerated 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"`
}
复制代码
视频中进行的改动部分
//fmt.Printf("%s\n")
var dictResponse DictResponse
err = json.Unmarshal(bodyText, &dictResponse)//反序列化关键,记得&符号,取地址符
if err != nil {
log.Fatal(err)
}
fmt.Printf("%#v\n", dictResponse)//更加详细的进行打印信息
复制代码
2.5在线词典 - 打印结果
//完整代码
package 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"`
}
// DictResponse
type AutoGenerated 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(good string) {
client := &http.Client{}
request := DictRequest{TransType: "en2zh", Source: "good"}
buf, err := json.Marshal(request)
if err != nil {
log.Fatal(err)
}
//创建一个新的io.Reader类型的变量data, 并将buf这个字节数组作为参数传入bytes.NewReader()函数, 以此来创建一个新的io.Reader对象。这个io.Reader对象可以读取buf中的数据,并将读取到的数据赋值给data
var data = bytes.NewReader(buf) //现在返回的是byte数组而不是字符串
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)
}
//作用:当前函数执行结束时,自动关闭resp.Body这个io.ReadCloser接口类型的对象
defer resp.Body.Close() //调用resp.Body.Close()函数的执行延迟到当前函数执行结束后
//ReadAll函数返回两个值,一个是读取的字节数组,赋值给bodyText,另一个是error类型的错误值
bodyText, err := ioutil.ReadAll(resp.Body) //读取数据
if err != nil {
log.Fatal(err)
}
if resp.StatusCode != 200 { //判断接口的状态码是否为200
log.Fatal("bad StatusCode:", resp.StatusCode, "body", string(bodyText))
}
var dictResponse AutoGenerated
err = json.Unmarshal(bodyText, &dictResponse)
if err != nil {
log.Fatal(err)
}
//选取需要的部分
fmt.Println(good, "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)
}
good := os.Args[1]
query(good)
}
通过代码样例学会了go语言的基础