作业---猜字谜
使用
fmt.Scanf来简化猜字谜的输入操作
课程中的输入操作
reader := bufio.NewReader(os.Stdin)
input, err := reader.ReadString('\n')
input = strings.TrimSuffix(input, "\r\n")
guess, err := strconv.Atoi(input)
按照课程中的方法是用bufio的方式,从系统的stdin中读取内容到reader这个buf里
然后再从reader中读取字符串以\n结尾。接着用TrimSuffix函数镜像分割
由于Windows上的结尾符合为
\r\n,而类unix系统的结尾符号都是\n,所以这里和视频里有所出入
获取到字符串之后,又使用strcov.Atoi函数,将字符串转化为数字
对比C语言中的scanf,可以看得出这一通操作很繁琐。
fmt.Scanf改进
var guess int
_, err := fmt.Scanf("%d\n", &guess)
可以看到相比bufio TrimSuffix Atoi的方式
改进后直接只用了一个Scanf便完成了相应的操作
作业---字典
增加一个Api调用
课程视频中使用的是彩云翻译的Api接口
而作业是用另外的接口实现,这里我选的是百度翻译api
type DictRequest struct {
query string
from string
to string
appid string
salt string
sign string
}
type DictResponse struct {
From string `json:"from"`
To string `json:"to"`
TranslateResult []struct {
Src string `json:"src"`
Dst string `json:"dst"`
} `json:"trans_result"`
}
func query(query string) (DictResponse, error) {
request := DictRequest{
query: query,
from: "auto",
to: "zh",
appid: appid,
salt: salt,
sign: getSign(query),
}
data := url.Values{}
data.Set("q", request.query)
data.Set("from", request.from)
data.Set("to", request.to)
data.Set("appid", request.appid)
data.Set("salt", request.salt)
data.Set("sign", request.sign)
u, err := url.ParseRequestURI(host)
if err != nil {
log.Fatal(err)
return DictResponse{}, errors.New("bad response")
}
u.RawQuery = data.Encode()
req, err := http.NewRequest("GET", u.String(), nil)
if err != nil {
log.Fatal(err)
return DictResponse{}, errors.New("bad response")
}
client := &http.Client{}
req.Header.Add("Accept", "*/*")
req.Header.Add("Host", "fanyi-api.baidu.com")
req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
resp, err := client.Do(req)
if resp.StatusCode != 200 {
log.Fatal("bad StatusCode", resp.StatusCode)
return DictResponse{}, errors.New("bad response")
}
if err != nil {
log.Fatal(err)
return DictResponse{}, errors.New("bad response")
}
defer resp.Body.Close()
bodytext, err := io.ReadAll(resp.Body)
if err != nil {
log.Fatal(err)
return DictResponse{}, errors.New("bad response")
}
var response DictResponse
err = json.Unmarshal(bodytext, &response)
if err != nil {
log.Fatal(err)
return DictResponse{}, errors.New("bad response")
}
return response, nil
}
这里只放了部分的代码,个人信息都没展示出来。
根据百度的Api手册,百度的翻译Api用Get方法将参数以param的形式传入,然后返回一个json作为结果
传入的参数有一个值得提一嘴的是sign,这个参数需要用百度提供的appid secret再配合需要查询的字符串和查询随机生成的一段字符串,通过字符串拼接的方式计算出MD5码作为sign传入,以达到服务校验的目的
两个api同时请求加快查询
通过同时请求两个api,哪个先得到结果,就显示哪个的结果,这样可以保证api请求的基本速度。
通过对api请求的封装我们可以将主逻辑简化为如下流程
func main() {
word := getWord()
results := make(chan common.Result, 1)
go func() {
var result common.Result
var err error
for {
result, err = baiduapi.Query(word)
if err == nil {
break
}
}
results <- result
}()
go func() {
var result common.Result
var err error
for {
result, err = caiyunapi.Query(word)
if err == nil {
break
}
}
results <- result
}()
select {
case result := <-results:
fmt.Println(result.Src)
fmt.Println(result.Dst)
break
}
}
我们定义了一个channel用作协程返回结果。开两个协程,分别对应两个api的请求操作
在主协程中,我们使用select监听result channel,一旦有协程得到结果向channel中添加了数据,直接将该数据打印