【青训营】go语言入门笔记/第一天作业 | 青训营笔记

250 阅读4分钟

这是我参与「第三届青训营 -后端场」笔记创作活动的的第1篇笔记

课程笔记

简介

  • 特性:

    • 高性能、高并发

    • 语法简单、学习曲线平缓

       package main
       import "net/http"
       ​
       // 支持静态文件访问的服务器
       func main(){
           http.Handle("/", http.FileServer(http.Dir(".")))
           http.ListenAndServe(":8080", nil)
       }
      
    • 丰富的标准库

    • 完善的工具链

    • 静态链接

    • 快速编译

    • 跨平台

    • 垃圾回收

  • 应用场景

入门

开发环境

基础语法

  • 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的方法还在实现,感觉可以将它当作一个消息队列使用,也是先进先出这样应该也是可以谁快谁输出的。

总结

感觉第一节课难度还没有很大,但是时间确实有、充实,希望八号之后的几天消化时间可以快速在把基础知识过一遍,也结合这几天的内容消化一下。