这是我参与「第三届青训营 -后端场」笔记创作活动的的第1篇笔记
课程笔记
简介
-
特性:
-
高性能、高并发
-
语法简单、学习曲线平缓
package main import "net/http" // 支持静态文件访问的服务器 func main(){ http.Handle("/", http.FileServer(http.Dir("."))) http.ListenAndServe(":8080", nil) } -
丰富的标准库
-
完善的工具链
-
静态链接
-
快速编译
-
跨平台
-
垃圾回收
-
-
应用场景
入门
开发环境
-
安装go语言
-
配置go的集成开发环境
基础语法
-
hello word
package main import "fmt" func main(){ fmt.Println("hello world") }go run main.go # 运行 go build main.go # 编译 -
变量
package main import { "fmt" "math" } func main(){ var a = "intial" var b, c int = 1, 2 var d = true var e float64 f := float32(e) g := a+"foo" const s string = "constant" const h = 50000 } -
if else
if xxx { ... } else { ... } -
for循环——仅有一种方法,有continue和break
-
switch——可以不用break,可以取代if else
-
数组
var a [5]int b := [5]int{1,2,3,4,5} var twoD[2][3]int // 更多使用切片 -
切片——可变长度的数组,使用make函数创建
-
map——使用最频繁,完全无序的
m := make(map[string]int) -
range——快速遍历,返回索引和对应位置的值
-
函数——一般返回多个值
-
指针——对常用的参数进行修改,相对于C/C++比较有限
-
结构体——带类型的字段的集合
-
结构体方法
-
错误处理——使用单独的返回值处理错误信息,可以在函数返回值里面加一个error
-
字符串操作
-
字符串格式化
-
json处理——json.Marshal、json.Unmarshal
-
时间处理——time.now()
-
数字解析
-
进程信息——os.Args:命令行参数、os.Getenv、os.Setenv、exec.Command().CombinedOutput()
实战
课后作业
1,猜数字
需求:利用fmt.scanf获取输入
package main
import (
"fmt"
"math/rand"
"time"
)
func main() {
// 生成随机数
maxNum := 100
rand.Seed(time.Now().UnixNano()) // 随机数种子:利用时间戳
secretNumber := rand.Intn(maxNum)
fmt.Println("Please input your guess")
var guess int
for {
// 获取输入
_, err := fmt.Scanf("%d\n", &guess)
if err != nil {
fmt.Println("sumething is error")
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
}
}
}
这一题就感觉比较入门了,但是要看一下fmt.scanf的使用,反正我当时也懵了一下:
- fmt.Scanf()可以按照指定的格式输入
- 输入值之间使用空格隔开
- 原型:
func Scanf(format string, a ...interface{}) (n int, err error) - 其返回值是成功扫描的条目个数和遇到的任何错误
- 需要和scanf和scanln做对比:
函数 参数 使用细节 返回值 Scanf 格式化字符串, 内存空间地址(可传多个) 传入的值必须满足格式的要求 保存成功的值数量, 保存存失败的原因 Scan 内存空间地址(可传多个) 识别换行符为空格 同上 Scanln 内存空间地址(可传多个) 识别换行符为完成 同上 - 当需要获取用户输入的文本时,可以使用扫描函数
- scan识别换行符,scanln不识别,scanf需要传入格式化字符串参数
- 都返回成功数量和失败的原因
- 输入类型和指定类型不符合时,值为类型的默认值
2/3. 命令行翻译
- 需求:照猫画虎在做一个另一种翻译引擎的支持;并行两个请求提高行营速度
# 其他还是之前的main函数
var wg sync.WaitGroup
type my_DictRequest struct {
Text string `json:"text"`
Language string `json:"language"`
}
type my_DictResponse struct {
Words []struct {
Source int `json:"source"`
Text string `json:"text"`
PosList []struct {
Type int `json:"type"`
Phonetics []struct {
Type int `json:"type"`
Text string `json:"text"`
} `json:"phonetics"`
Explanations []struct {
Text string `json:"text"`
Examples []struct {
Type int `json:"type"`
Sentences []struct {
Text string `json:"text"`
TransText string `json:"trans_text"`
} `json:"sentences"`
} `json:"examples"`
Synonyms []interface{} `json:"synonyms"`
} `json:"explanations"`
Relevancys []interface{} `json:"relevancys"`
} `json:"pos_list"`
} `json:"words"`
Phrases []interface{} `json:"phrases"`
BaseResp struct {
StatusCode int `json:"status_code"`
StatusMessage string `json:"status_message"`
} `json:"base_resp"`
}
func my_query(word string) {
client := &http.Client{}
request := my_DictRequest{Text: word, Language: "en"}
// json序列化,变成一个buf数组
buf, err := json.Marshal(request)
if err != nil {
log.Fatal(err)
}
var data = bytes.NewReader(buf)
req, err := http.NewRequest("POST", "https://translate.volcengine.com/web/dict/match/v1/?msToken=&X-Bogus=DFSzswVLQDaeaNhSSWB-dVXAIQ2m&_signature=_02B4Z6wo00001cxLkYgAAIDAr0FR4cDTHbHMS5UAABFm5NpCh-Tx4tcKE-VeKRMDREGbDS8YRskZap6M34ZyhM7JDxuy8CEACdcWF5Mq5SBJ5Dr76g0wlItzNw1v7CLKNh-9kqscOEfLE3u430", data)
if err != nil {
log.Fatal(err)
}
req.Header.Set("authority", "translate.volcengine.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("content-type", "application/json")
req.Header.Set("cookie", "x-jupiter-uuid=16519083713125572; i18next=zh-CN; ttcid=9f24ca180618456386e814507b52444742; tt_scid=AuamOFVGVJYlMWzgQhExcsbSFN5bLpUSxaVpJwVcWq4sr5CHioC03YJgeqrFLqGD0469; s_v_web_id=verify_c86160ee934401b0aa1fd7f1e4a28af1; _tea_utm_cache_2018=undefined")
req.Header.Set("origin", "https://translate.volcengine.com")
req.Header.Set("referer", "https://translate.volcengine.com/translate?category=&home_language=zh&source_language=detect&target_language=zh&text=else")
req.Header.Set("sec-ch-ua", `" Not A;Brand";v="99", "Chromium";v="101", "Microsoft Edge";v="101"`)
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", "same-origin")
req.Header.Set("user-agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.41 Safari/537.36 Edg/101.0.1210.32")
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 my_DictResponse
err = json.Unmarshal(bodyText, &dictResponse)
if err != nil {
log.Fatal(err)
}
for _, word := range dictResponse.Words {
for _, polist := range word.PosList {
for _, item := range polist.Explanations {
fmt.Println(item.Text)
}
}
}
wg.Done()
}
func main() {
if len(os.Args) != 2 {
fmt.Fprintf(os.Stderr, `usage: simpleDict WORD
example: simpleDict hello
`)
os.Exit(1)
}
word := os.Args[1]
wg.Add(1)
go query(word)
go my_query(word)
wg.Wait()
}
- 主要是实现了火山翻译的另一种方法,也是由于其和彩云的负载是类似的,都是json格式。也看了一下百度和有道的,那个负载格式挑了半天没有调整出来,就暂时放弃了。
- 关于并发执行方面利用的是
sync.WaitGroup,其主要应用于线程同步,主要的方法是Add、Done、Wait。- 个人简单的理解就相当于C++的shared_ptr?每次add会增加一个计数,done则减少一个计数。而wait则是阻塞住,直到waitgroup的数量为0。
- 所以在主函数中我是启动了两个协程,但是只进行一次add(1)操作,这样两个协程无论任何一个执行到done都会直接退出主函数。这样的话两个并行执行的话,就是谁快谁先输出了?
- 但是有问题我没有想的很清楚,在每个线程done之前,会有fmt.println(),理论上会不会产生两个结果交替执行的情况呢?我尝试了几次,结果如下:
PS E:\GoPath\byte\go-by-example> go run .\simpledict\my\main.go world world UK: [wəːld] US: [wɝld] n.世界;地球;宇宙;人类,全世界的人;领域;世间;多数;大量;(常作W-)地球的某一处 a.世界的 PS E:\GoPath\byte\go-by-example> go run .\simpledict\my\main.go world world UK: [wəːld] US: [wɝld] n.世界;地球;宇宙;人类,全世界的人;领域;世间;多数;大量;(常作W-)地球的某一处 a.世界的 PS E:\GoPath\byte\go-by-example> go run .\simpledict\my\main.go world (常作the world)地球,世界;(the world)地球上的所有人(和社会);(作为修饰语,代表同级中最重要的人或事物之一)举世,世界(范围);(尤指可能或确有生命存在的)星球,天体;特定的地区或国家;特定的历史时期;生物群;特定活动领域,界,圈子;(one's world)(指个人的生活及活动)个人世界;社会生活,社 会交往;俗界,世事;今世,来世 PS E:\GoPath\byte\go-by-example> go run .\simpledict\my\main.go world world UK: [wəːld] US: [wɝld] n.世界;地球;宇宙;人类,全世界的人;领域;世间;多数;大量;(常作W-)地球的某一处 a.世界的 PS E:\GoPath\byte\go-by-example> go run .\simpledict\my\main.go world world UK: [wəːld] US: [wɝld] n.世界;地球;宇宙;人类,全世界的人;领域;世间;多数;大量;(常作W-)地球的某一处 a.世界的 PS E:\GoPath\byte\go-by-example> go run .\simpledict\my\main.go world world UK: [wəːld] US: [wɝld] n.世界;地球;宇宙;人类,全世界的人;领域;世间;多数;大量;(常作W-)地球的某一处 a.世界的 PS E:\GoPath\byte\go-by-example> go run .\simpledict\my\main.go world world UK: [wəːld] US: [wɝld] n.世界;地球;宇宙;人类,全世界的人;领域;世间;多数;大量;(常作W-)地球的某一处 a.世界的 PS E:\GoPath\byte\go-by-example> go run .\simpledict\my\main.go world (常作the world)地球,世界;(the world)地球上的所有人(和社会);(作为修饰语,代表同级中最重要的人或事物之一)举世,世界(范围);(尤指可能或确有生命存在的)星球,天体;特定的地区或国家;特定的历史时期;生物群;特定活动领域,界,圈子;(one's world)(指个人的生活及活动)个人世界;社会生活,社 会交往;俗界,世事;今世,来世 - 这个问题我会再查阅一下资料去了解一下,关于使用chan的方法还在实现,感觉可以将它当作一个消息队列使用,也是先进先出这样应该也是可以谁快谁输出的。
总结
感觉第一节课难度还没有很大,但是时间确实有、充实,希望八号之后的几天消化时间可以快速在把基础知识过一遍,也结合这几天的内容消化一下。