一. 实战案例课后作业
1. 修改猜谜游戏的代码并用fmt.scanf来实现并简化
首先粘贴原代码
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
}
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
}
}
}
我们可以看到原代码共调用7个包来实现猜数的功能,其中"fmt"用于打印及其他基础语法"math/rand"及"time"用于生成随机数,"strconv"和"strings"用于对读取的数值进行处理以转化为数字,"bufio"和"os"创建了一个新的 bufio.Reader 对象,该对象用于从 os.Stdin 标准输入,通常是键盘)读取数据,若要简化并使用fmt.scanf,可以优化掉"bufio"和"os"包及相关代码。
我们主要修改输入部分及对输入的处理,见以下代码:
var input string
_, err := fmt.Scanf("%s\n", &input)
if err != nil {
fmt.Println("An error occurred while reading input. Please try again", err)
continue
}
第一行我们首先定义一个input变量为string类型,第二行代码使用fmt.Scanf函数从键盘读取一个字符串,并将其存储在input变量中fmt.Scanf函数返回两个值:成功读取的数据项数和可能的错误,在这里我们使用 _ 忽略了第一个返回值(成功读取的数据项数),因为我们只关心是否有错误发生。
input = strings.TrimSpace(input)
guess, err := strconv.Atoi(input)
在以上代码中,我们使用了string包中的Trimspace函数,其作用是移除 input 字符串两端的所有空白字符,然后赋值回 input,input的值会被更新为去掉两端空白后的字符串,这个函数在处理用户输入时非常有用,因为用户可能会在输入的开始或结束处不小心添加额外的空格,strings.TrimSpace 可以确保你的程序不会因为这些额外的空格而出错;strconv.Atoi的作用则是将input中的字符转化为int形式以便后续的大小比较。
后续部分则并没有什么差别,最后我们粘贴出整条代码供大家参考:
package main
import (
"fmt"
"math/rand"
"strconv"
"strings"
"time"
)
func main() {
maxNum := 100
rand.Seed(time.Now().UnixNano())
secretNumber := rand.Intn(maxNum)
fmt.Println("Please input your guess")
for {
var input string
_, err := fmt.Scanf("%s\n", &input)
if err != nil {
fmt.Println("An error occurred while reading input. Please try again", err)
continue
}
input = strings.TrimSpace(input)
guess, err := strconv.Atoi(input)
if err != nil {
fmt.Println("Invalid input. Please enter an integer value")
continue
}
fmt.Println("Your 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
}
}
}
若要进一步简化,可以尝试用fmt.scanf直接读取int类型,将main函数中部分功能独立成func也有助于后期代码维护。
2. 修改词典中的最终代码,增加一种新的翻译引擎支持
经过实践,仅实现了百度翻译和搜狗翻译的效果,其他在线翻译均在找负载和预览步骤或json请求翻车T-T
要实现在go中调用百度翻译,首先,要在网页版的百度翻译界面右键打开检查,并打开最上方的网络界面,此时在百度翻译的翻译框内输入 hello ,可以看到左侧出现大量项目,从下往上寻找 sug(多次尝试及查找资料后发现,需要在翻译框内输入查找内容后再输入一个空格并删掉空格才会出现正确的 sug )。
找到 sug 后,对其鼠标右键,找到复制,windows选择复制为cURL(bash),我们便可得到一大串Json,之后我们需要用到工具Convert curl to Go (curlconverter.com),该网站可以将我们复制到的Json转化为我们需要的请求形式:
package main
import (
"fmt"
"io"
"log"
"net/http"
"strings"
)
func main() {
client := &http.Client{}
var data = strings.NewReader(`kw=hello`)
req, err := http.NewRequest("POST", "https://fanyi.baidu.com/sug", data) //创建请求
if err != nil {
log.Fatal(err)
}
req.Header.Set("Accept", "application/json, text/javascript, */*; q=0.01") //设置请求头
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("Connection", "keep-alive")
req.Header.Set("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8")
req.Header.Set("Cookie", "__bid_n=1845a6dd63ffc82cf04207; BAIDUID=685A9238812183856E74CA05354AEA47:FG=1; BAIDUID_BFESS=685A9238812183856E74CA05354AEA47:FG=1; FEID=v10-b402c3fa2de0cb66c2d7c2e247c2820d2eb725d2; __xaf_fpstarttimer__=1671167593498; __xaf_thstime__=1671167593644; __xaf_fptokentimer__=1671167593698; FPTOKEN=aA5a9vViK8Vk3pZmX0sbQfyvFgRJ4/IswLk+lmwlflPXt9NffpruSzRf2dA0Zn+yNVpfEkOwTEkDoCD57hgxYBCaKgw8Idh2cWl35GLb6DGYhlGmrzf1mLR1QY5itGuAnHKcHoMPjoJ/3ZqLUZpVlWfh2CpicNXipGGb4A4VLuEDgvCVyO29/BiJjQIPQVYrux8R0N2oH9on+C1cx88BDUx+yHyeNYPiQDmnF7NYFQz0794ATQFRy6GhUaTQotXIJAdJOP3aIn8vv5dtaFuZlDYnoZei1RH3wJVIX8fcvPLtEhCoJD8AJmXG07gh9ROhvaU7c7XEOLs5s4ESlf4RN5fziED75CLK2wKXF6kbTl/804+k1A10mbXRO4nhXeI/a1bnqbdIh0ZY9SCRl7F+RGQMi3JRBqPYMQA6lLr5EOUcpR8FvLDtkK/s/CYt04T8|WrjwkUF6GeNesxO1u3plEPLpDU8N0TxDE+H8zoCQhcI=|10|d7ba2fc5cddbbbec92763b9e50cb0557; REALTIME_TRANS_SWITCH=1; FANYI_WORD_SWITCH=1; HISTORY_SWITCH=1; SOUND_SPD_SWITCH=1; SOUND_PREFER_SWITCH=1; Hm_lvt_64ecd82404c51e03dc91cb9e8c025574=1690787492; Hm_lpvt_64ecd82404c51e03dc91cb9e8c025574=1690802984; ab_sr=1.0.1_ZjkxNDBmMzdkNGM0YjEyMjkxOGU3NmUzMzBlNjM3Y2VlMWQ1NTQ2ZDYyM2E2MGFlYjI5ZDY0NzNiNjlhMzY3ZDEwNjllZmViYzFkZmI2ZmJkNjMyZmE2YjdkNWM2NzE2YjFkMjg1ZGNhYzUwZTYxZWMwYTBmYzkxNzFkNTBmNzMwNWRhOTc3Njg1NDcxNmFhYmRhY2UyNzhhZTlhZDA2MA==")
req.Header.Set("Origin", "https://fanyi.baidu.com")
req.Header.Set("Referer", "https://fanyi.baidu.com/")
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.188")
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)
}
复制下方代码并粘贴进编辑器内,我们便完成了第一步,可以尝试运行:
由上方的第十三行代码可知,百度翻译的负载仅为 kw 这一项
var data = strings.NewReader(`kw=hello`)
因此我们无需创建结构体,而是使用下代码来实现负载:
var s1 string = "kw=wink"
var data = strings.NewReader(s1)
我们这样修改main函数的请求部分
client := &http.Client{}
var inport string = "kw=" //此处于课程示例输入方式不同,若不添加=会出现错误
inport += word
var data = strings.NewReader(inport)
req, err := http.NewRequest("POST", "https://fanyi.baidu.com/sug", data)
if err != nil {
log.Fatal(err)
接下来要生成DictResponse,我们需要用到工具JSON转Golang Struct - 在线工具 - OKTools,在sug中选择预览,并对第一项复制值,粘贴到工具中,并选择嵌套,我们便得到了需要的结构体,免去了制定复杂结构体的过程。
将其粘贴到代码中并将名称改为
DictResponse
最后我们要对打印的结果进行处理,我们要将原来的main函数修改为query函数
//func main()
func query(word string)
并设置打印路径:
fmt.Printf("translate:\n\t")
for i, item := range dictResponse.Data[0].V {
if item == 'n' && i > 0 && dictResponse.Data[0].V[i-1] == ' ' || item == 'v' {
fmt.Printf("\n\t")
}
fmt.Printf("%c", item)
}
fmt.Println()
最后创建新的main函数来调用query函数:
func main() {
var word string
fmt.Scanln(&word)
for word != "EOF" {
query(word)
fmt.Scanln(&word)
}
fmt.Println("over")
}
若使用搜狗翻译,则可采用相同步骤仅在路径设置及json调用等方面有些许不同