golang基础:基础语言|青训营笔记

118 阅读5分钟

golang基础:基础语言|青训营笔记

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

课前导学链接

【Go 语言原理与实践学习资料】第三届字节跳动青训营-后端专场

本节课内容为Go语言基础和三个小项目实战,课程代码在以下网址中

课程代码

课程ppt链接

Go语言基础上手

Go 的特点

  1. 高性能、高并发

  2. 语法简单、学习曲线平缓

    实现可以承载静态文件访问的高性能服务器

    package main
    import "net/http"
    func main() {
      // 在 http 标准库里面内建路由,将 / 映射到一个静态文件 处理的实现
      http.Handle("/", http.FileServer(http.Dir(".")))
      // 增添 8080 端口,并且启动服务器
      http.ListenAndServe(":8080", nil)
    }
    
  3. 丰富的标准库

  4. 完善的工具链

    内置单元测试框架

  5. 静态链接

    在go语言里,所有的编译结果默认都是静态链接的,只要拷贝编译之后唯一一个可执行文件,不需要附属任何东西就能部署运行

  6. 快速编译

    go语言拥有静态语言里面几乎最快的编译速度

  7. 跨平台

    能在各种奇奇怪怪的 平台运行,在笔记本编译一个二进制文件,拷贝到路由器上运行,而无需配置交叉编译环境

  8. 垃圾回收

    写代码的时候无需考虑内存的分配与释放

Go 语言基础

第一部分的内容基本可以在以下链接中找到,建议基础薄弱的同学阅读以下链接。

Go by Example 中文版

此外贴出一个我非常推荐的一个Go语言教程,Go语言之旅

Go 语言之旅

小项目实战

项目一:猜谜游戏


第一个小项目猜数字游戏,这个项目比较简单,主要是联系一些基础语法使用,使用相应的包建议浏览官方文档,此项目用到了math/rand包。

注意:使用随机数要设置随机数种子,否则将导致随机数永远是同一个数

func main(){
  maxNum := 100
  rand.Seed(time.Now().UnixNano())
  secretNum := rand.Intn(maxNum)
  fmt.Println("the secret number is :", secretNum)	
}

项目二:简单词典


第二个小项目简单词典,利用彩云小译的查词API来查询英语单词。

首先展示了如何利用浏览器开发人员工具获取HTTP请求的详细信息(网络部分找到dict请求),复制dict请求的cURL命令后,接着利用以下网站将相应的cURL命令转换为Go语言代码。

Convert curl commands to code

对于请求结果的处理需要在Go中创建相应的结构体,手动编写非常麻烦,这里利用以下在线工具中的json2go工具直接生成对应结构体。

在线工具 - OKTools

这个项目整体难度也不大,但是其利用公共API的方式以及对于代码生成工具的利用非常值得学习。

项目三:SOCKS5代理


第三个小项目SOCKS5代理,这个项目代码量比前两个都要大也更为复杂,总计约200行。

首先简单介绍SOCK5代理的原理。

socket5

代码总共四个函数,main(),process(),auth(),connect(),主要部分是认证函数auth()和连接函数connect()。代码内容大多都是些读取数据,在各种数据格式之间进行转换。这里不进行赘述,建议自行查看源代码理解。

课后习题

题目一


修改第一个例子猜谜游戏里的最终代码,使用fmt.Scanf()来简化代码实现。

首先到官网查询fmt.Scanf()的文档

image-20220507201723268

其实也就跟C语言里的scanf用法差不多,只不过额外返回了一个error用于错误处理。

直接列出修改前后的代码

image-20220507203501836

题目二


修改第二个例子命令行词典里的最终代码,增加另一种翻译引擎的支持。

使用有道翻译

结构体:

type YoudaoResp struct {
  TranslateResult [][]struct {
    Tgt string `json:"tgt"`
    Src string `json:"src"`
  } `json:"translateResult"`
  ErrorCode   int    `json:"errorCode"`
  Type        string `json:"type"`
  SmartResult struct {
    Entries []string `json:"entries"`
    Type    int      `json:"type"`
  } `json:"smartResult"`
}

有道有防爬加密,需要构造请求参数

package main

import (
  "crypto/md5"
  "encoding/hex"
  "encoding/json"
  "fmt"
  "io/ioutil"
  "log"
  "math/rand"
  "net/http"
  "os"
  "strconv"
  "strings"
  "time"
)

func main() {
  if len(os.Args) != 2 {
    fmt.Fprintf(os.Stderr, `usage: simpleDict WORD
example: simpleDict hello
		`)
    os.Exit(1)
  }
  word := os.Args[1]
  queryByYoudao(word)
}

func queryByYoudao(word string) {
  t := time.Now().UnixMilli()
  lts := strconv.FormatInt(t, 10)
  rand.Seed(time.Now().UnixNano())
  salt := lts + strconv.Itoa(rand.Intn(9))
  sign := encrypt("fanyideskweb" + word + salt + "Ygy_4c=r#e#4EX^NUGUc5")
  client := &http.Client{}
  var data = strings.NewReader("i=" + word + "&from=AUTO&to=AUTO&smartresult=dict&client=fanyideskweb&salt=" + salt + "&sign=" + sign + "&lts=" + lts + "&bv=d60b9bede0ddd264422f25a5e061c49a&doctype=json&version=2.1&keyfrom=fanyi.web&action=FY_BY_REALTlME")
  req, err := http.NewRequest("POST", "https://fanyi.youdao.com/translate_o?smartresult=dict&smartresult=rule", 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-US;q=0.8,en;q=0.7")
  req.Header.Set("Cache-Control", "no-cache")
  req.Header.Set("Connection", "keep-alive")
  req.Header.Set("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8")
  req.Header.Set("Cookie", "P_INFO=null; OUTFOX_SEARCH_USER_ID=-158590838@10.110.96.160; OUTFOX_SEARCH_USER_ID_NCOO=2106315215.8019254; DICT_UGC=be3af0da19b5c5e6aa4e17bd8d90b28a|; JSESSIONID=abcUFb505Z1AO_Umr8Ccy; ___rl__test__cookies=1651913317638")
  req.Header.Set("Origin", "https://fanyi.youdao.com")
  req.Header.Set("Pragma", "no-cache")
  req.Header.Set("Referer", "https://fanyi.youdao.com/?keyfrom=dict2.top")
  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 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.127 Safari/537.36")
  req.Header.Set("X-Requested-With", "XMLHttpRequest")
  req.Header.Set("sec-ch-ua", `" Not A;Brand";v="99", "Chromium";v="100", "Google Chrome";v="100"`)
  req.Header.Set("sec-ch-ua-mobile", "?0")
  req.Header.Set("sec-ch-ua-platform", `"macOS"`)
  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)
  }
  fmt.Printf("%s\n", bodyText)
  var respEntity YoudaoResp
  err = json.Unmarshal(bodyText, &respEntity)
  if err != nil {
    log.Fatal(err)
  }
  //fmt.Printf("%#v\n", respEntity)
  fmt.Println(word, "SRC:", respEntity.TranslateResult[0][0].Src, "TGT:", respEntity.TranslateResult[0][0].Tgt)
  for _, item := range respEntity.SmartResult.Entries {
    fmt.Println(item)
  }
}

func encrypt(str string) string {
  h := md5.New()
  h.Write([]byte(str))
  return hex.EncodeToString(h.Sum(nil))
}

题目三

在上一步骤的基础上,修改代码实现并行请求两个翻译引擎来提高响应速度。

使用Go协程与WaitGroup来实现并发,只需对main()函数做一些修改如下

func main() {
  if len(os.Args) != 3 {
    fmt.Fprintf(os.Stderr, `usage: simpleDict WORD
	example: simpleDict hello
			`)
    os.Exit(1)
  }
  w1 := os.Args[1]
  w2 := os.Args[2]

  var wg sync.WaitGroup
  wg.Add(2)
  go func() {
    defer wg.Done()
    queryCaiyun(w1)
  }()
  go func() {
    defer wg.Done()
    queryYoudao(w2)
  }()
  wg.Wait()

}

运行结果

image-20220507204540921