第一天-Go语言基础 | 青训营笔记

183 阅读6分钟

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

由于对go不算太熟悉,只能将课程中很多细的知识记了下来

笔记可能有点笼统

1.什么是Go

image.png

右图代码作用:开启服务器

第8行: 把“/”的路由指向一个静态的文件

第9行:监听8080端口,且启动服务器

1.1哪些公司在使用Go

image.png

2.Go入门

2.1.开发环境的配置

2.2基础语法

2.2.1 输出

image.png

代码: 第1行:表示该文件属于main包的一部分 main包表示程序的入口文件

第3-5行:导入标准库的包

第7-9行:执行函数

image.png

go run 运行程序

go build 编译成二进制

2.2.2基础语法-变量与常量

ps:Go语言是强类型语言 每一个变量都有自己的类型

image.png

数据类型: 整型类型,字符串类型,浮点类型,布尔类型等

定义变量的方式:

方式1:显示给出数据,自动推导类型 -----------参考第10行代码

方式2:显示给出数据类型 -----------参考第12行代码

方式3:变量名 := 值 -----------参考第18行代码

定义常量:

将var 改成 const 即可

ps:常量没有确定的类型,会根据程序的上下文自动确定类型

2.2.3基础语法-if else

image.png

语法与其他语言差不多

注意:

代码第7行 if后写条件不跟括号 如果写了括号 在保存时编辑器会自动去掉

2.2.4基础语法-循环

ps:go中只有一种循环 ---》 for循环

image.png

代码8-11 代表死循环 即 for中不写任何条件

for中的条件 也 不跟 括号

2.2.5基础语法-switch

ps:switch中的条件 也 不跟 括号

image.png

注意:

不用显式在分支中给出break; 执行完当前分支后会自动往下去执行 --- 》参考代码18-19

switch后不跟条件 则可以在case后给出选择条件也可以完成switch的功能 --- 》参考代码24-30

2.2.6基础语法-数组

image.png

定义数组的方式: 7,11,14

ps:定长的数组

2.2.7基础语法-切片

image.png

ps:可变长的数组

注意:

定义 切片 的方式 --》代码第7行,第11行,第14行

使用append时,要 重新赋值 给原切片 --》代码14-15行

切片间的数据拷贝 --》代码第19

2.2.8基础语法-map

image.png

定义map ---》 代码6,19-20 基础格式:map[key的数据类型]value的数据类型

设置键值对 ---》 代码7-8

根据键取出值 ---》 代码11-12

注意: map 中 元素 完全无序

判断map中是否存在key: 代码第14行 返回值为: 元素值本身,是否存在

2.2.9基础语法-range

功能: 遍历

image.png

ps: 遍历数组:

代码8-13行: 第一个值 元素下标 第二个值 元素本身

遍历map:

代码17-19行: 第一个值key 第二个值value

2.2.10基础语法-函数

image.png

ps:

参数中 变量的类型 后置 ---》代码第5行

函数可以 单值 返回 ---》代码第5行 参数后定义返回值类型

函数可以 多值 返回 ---》代码第13行 参数后定义需要返回的数据

2.2.11基础语法-指针

image.png

2.2.12基础语法-结构体

image.png

定义结构体: 代码第5-8行

使用结构体:代码第11-13行 可以不对结构体所有的元素进行初始化,没有被初始化会默认置为null 使用.运算符去方位结构体的内容

2.2.13基础语法-结构体方法

image.png

ps:

参考Java中的类

注意 代码 第24-90 行 方法的定义与 普通 方法的 区别

2.2.14基础语法-错误处理

image.png

ps: 方法得返回值类型中加入err类型 表示 该函数可能产生错误

nil表示定义但未赋值

注意:

第16行,第19行代码 函数返回两个返回值

第23行 需要用两个变量接收返回值

2.2.15基础语法-字符串处理

image.png

ps:根据效果推作用

2.2.15基础语法-字符串格式化

image.png

注意:

fmt.Printf函数可以打印任意类型变量 不用做区分

+v #v 都是对输出得内容更加详细化

2.2.16基础语法-JSON处理

image.png

ps:

结构体的字段开始第一个字母大写就可以了 不需要额外操作

json.Marshal(a)序列化 json.MarshalIndent(a)反序列化

代码第10行,第21行实现的效果

2.2.17基础语法-时间处理

image.png

ps:

根据效果推作用

格式化日期 代码 15 ,19

获取时间戳 代码24

2.2.18基础语法-数字解析

image.png

数字与字符串转化包 : strconv

代码12行 (字符串,字符串数字的进制 0表示自动推测,需要转换到的进制)

ParseXXX:字符串转数字 Atoi: 数字转字符串

2.2.19基础语法-进程信息

image.png

3.Go实战

3.1猜数游戏


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
      }

      //去除输入流中的\r\n
      input = strings.TrimSuffix(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
      }
   }
}

3.2在线词典

@XBI_BUTEFM{2MB1IK`{D)E.png

M5[DQ4PM)W$W%PXL`G{]DZX.png

0@M2U5JU7Z9D$3VX(QLWT)B.png

代码生成地址:curlconverter.com

解析Response Body生成结构体:oktools.net

根据cURL生成的代码:


package main

import (
   "bytes"
   "encoding/json"
   "fmt"
   "io/ioutil"
   "log"
   "net/http"
   "os"
)

type DictRequest struct {
   TransType string `json:"trans_type"`
   Source    string `json:"source"`
   UserID    string `json:"user_id"`
}

type DictResponse struct {
   Rc   int `json:"rc"`
   Wiki struct {
      KnownInLaguages int `json:"known_in_laguages"`
      Description     struct {
         Source string      `json:"source"`
         Target interface{} `json:"target"`
      } `json:"description"`
      ID   string `json:"id"`
      Item struct {
         Source string `json:"source"`
         Target string `json:"target"`
      } `json:"item"`
      ImageURL  string `json:"image_url"`
      IsSubject string `json:"is_subject"`
      Sitelink  string `json:"sitelink"`
   } `json:"wiki"`
   Dictionary struct {
      Prons struct {
         EnUs string `json:"en-us"`
         En   string `json:"en"`
      } `json:"prons"`
      Explanations []string      `json:"explanations"`
      Synonym      []string      `json:"synonym"`
      Antonym      []string      `json:"antonym"`
      WqxExample   [][]string    `json:"wqx_example"`
      Entry        string        `json:"entry"`
      Type         string        `json:"type"`
      Related      []interface{} `json:"related"`
      Source       string        `json:"source"`
   } `json:"dictionary"`
}

func query(word string) {
   client := &http.Client{}
   request := DictRequest{TransType: "en2zh", Source: word}
   buf, err := json.Marshal(request)
   if err != nil {
      log.Fatal(err)
   }
   var data = bytes.NewReader(buf)
   req, err := http.NewRequest("POST", "https://api.interpreter.caiyunai.com/v1/dict", data)
   if err != nil {
      log.Fatal(err)
   }
   req.Header.Set("Connection", "keep-alive")
   req.Header.Set("DNT", "1")
   req.Header.Set("os-version", "")
   req.Header.Set("sec-ch-ua-mobile", "?0")
   req.Header.Set("User-Agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.51 Safari/537.36")
   req.Header.Set("app-name", "xy")
   req.Header.Set("Content-Type", "application/json;charset=UTF-8")
   req.Header.Set("Accept", "application/json, text/plain, */*")
   req.Header.Set("device-id", "")
   req.Header.Set("os-type", "web")
   req.Header.Set("X-Authorization", "token:qgemv4jr1y38jyq6vhvi")
   req.Header.Set("Origin", "https://fanyi.caiyunapp.com")
   req.Header.Set("Sec-Fetch-Site", "cross-site")
   req.Header.Set("Sec-Fetch-Mode", "cors")
   req.Header.Set("Sec-Fetch-Dest", "empty")
   req.Header.Set("Referer", "https://fanyi.caiyunapp.com/")
   req.Header.Set("Accept-Language", "zh-CN,zh;q=0.9")
   req.Header.Set("Cookie", "_ym_uid=16456948721020430059; _ym_d=1645694872")
   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 DictResponse
   //缓存bodyText并写入结构体dictResponse
   //&不能漏 表示写入结构体dictResponse
   err = json.Unmarshal(bodyText, &dictResponse)

   if err != nil {
      log.Fatal(err)
   }

   fmt.Println(word, "UK:", dictResponse.Dictionary.Prons.En, "US:", dictResponse.Dictionary.Prons.EnUs)
   for _, item := range dictResponse.Dictionary.Explanations {
      fmt.Println(item)
   }
}

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

运行结果:

$0A97AOBPNM1%@`@C18FBJ6.png

3.3SOCKS5代理

SOCKS5代理-原理

image.png


package main

import (
   "bufio"
   "context"
   "encoding/binary"
   "errors"
   "fmt"
   "io"
   "log"
   "net"
)

const socks5Ver = 0x05
const cmdBind = 0x01
const atypIPV4 = 0x01
const atypeHOST = 0x03
const atypeIPV6 = 0x04

func main() {

   server, err := net.Listen("tcp", "127.0.0.1:1080")
   if err != nil {
      panic(err)
   }
   for {

      //返回一个连接
      client, err := server.Accept()

      if err != nil {
         log.Printf("Accept failed %v", err)
         continue
      }

      //go开启子线程
      go process(client)
   }
}

func process(conn net.Conn) {

   defer conn.Close()
   reader := bufio.NewReader(conn)
   err := auth(reader, conn)

   if err != nil {
      log.Printf("client %v auth failed:%v", conn.RemoteAddr(), err)
      return
   }
   err = connect(reader, conn)
   if err != nil {
      log.Printf("client %v auth failed:%v", conn.RemoteAddr(), err)
      return
   }
}

func auth(reader *bufio.Reader, conn net.Conn) (err error) {
   // +----+----------+----------+
   // |VER | NMETHODS | METHODS  |
   // +----+----------+----------+
   // | 1  |    1     | 1 to 255 |
   // +----+----------+----------+
   // VER: 协议版本,socks5为0x05
   // NMETHODS: 支持认证的方法数量
   // METHODS: 对应NMETHODS,NMETHODS的值为多少,METHODS就有多少个字节。RFC预定义了一些值的含义,内容如下:
   // X’00’ NO AUTHENTICATION REQUIRED
   // X’02’ USERNAME/PASSWORD

   ver, err := reader.ReadByte()
   if err != nil {
      return fmt.Errorf("read ver failed:%w", err)
   }
   if ver != socks5Ver {
      return fmt.Errorf("not supported ver:%v", ver)
   }
   methodSize, err := reader.ReadByte()
   if err != nil {
      return fmt.Errorf("read methodSize failed:%w", err)
   }
   method := make([]byte, methodSize)
   _, err = io.ReadFull(reader, method)
   if err != nil {
      return fmt.Errorf("read method failed:%w", err)
   }

   // +----+--------+
   // |VER | METHOD |
   // +----+--------+
   // | 1  |   1    |
   // +----+--------+
   _, err = conn.Write([]byte{socks5Ver, 0x00})
   if err != nil {
      return fmt.Errorf("write failed:%w", err)
   }
   return nil
}

func connect(reader *bufio.Reader, conn net.Conn) (err error) {
   // +----+-----+-------+------+----------+----------+
   // |VER | CMD |  RSV  | ATYP | DST.ADDR | DST.PORT |
   // +----+-----+-------+------+----------+----------+
   // | 1  |  1  | X'00' |  1   | Variable |    2     |
   // +----+-----+-------+------+----------+----------+
   // VER 版本号,socks5的值为0x05
   // CMD 0x01表示CONNECT请求
   // RSV 保留字段,值为0x00
   // ATYP 目标地址类型,DST.ADDR的数据对应这个字段的类型。
   //   0x01表示IPv4地址,DST.ADDR为4个字节
   //   0x03表示域名,DST.ADDR是一个可变长度的域名
   // DST.ADDR 一个可变长度的值
   // DST.PORT 目标端口,固定2个字节

   buf := make([]byte, 4)
   _, err = io.ReadFull(reader, buf)
   if err != nil {
      return fmt.Errorf("read header failed:%w", err)
   }
   ver, cmd, atyp := buf[0], buf[1], buf[3]
   if ver != socks5Ver {
      return fmt.Errorf("not supported ver:%v", ver)
   }
   if cmd != cmdBind {
      return fmt.Errorf("not supported cmd:%v", ver)
   }
   addr := ""
   switch atyp {
   case atypIPV4:
      _, err = io.ReadFull(reader, buf)
      if err != nil {
         return fmt.Errorf("read atyp failed:%w", err)
      }
      addr = fmt.Sprintf("%d.%d.%d.%d", buf[0], buf[1], buf[2], buf[3])
   case atypeHOST:
      hostSize, err := reader.ReadByte()
      if err != nil {
         return fmt.Errorf("read hostSize failed:%w", err)
      }
      host := make([]byte, hostSize)
      _, err = io.ReadFull(reader, host)
      if err != nil {
         return fmt.Errorf("read host failed:%w", err)
      }
      addr = string(host)
   case atypeIPV6:
      return errors.New("IPv6: no supported yet")
   default:
      return errors.New("invalid atyp")
   }
   _, err = io.ReadFull(reader, buf[:2])
   if err != nil {
      return fmt.Errorf("read port failed:%w", err)
   }
   port := binary.BigEndian.Uint16(buf[:2])

   dest, err := net.Dial("tcp", fmt.Sprintf("%v:%v", addr, port))
   if err != nil {
      return fmt.Errorf("dial dst failed:%w", err)
   }
   defer dest.Close()
   log.Println("dial", addr, port)

   // +----+-----+-------+------+----------+----------+
   // |VER | REP |  RSV  | ATYP | BND.ADDR | BND.PORT |
   // +----+-----+-------+------+----------+----------+
   // | 1  |  1  | X'00' |  1   | Variable |    2     |
   // +----+-----+-------+------+----------+----------+
   // VER socks版本,这里为0x05
   // REP Relay field,内容取值如下 X’00’ succeeded
   // RSV 保留字段
   // ATYPE 地址类型
   // BND.ADDR 服务绑定的地址
   // BND.PORT 服务绑定的端口DST.PORT
   _, err = conn.Write([]byte{0x05, 0x00, 0x00, 0x01, 0, 0, 0, 0, 0, 0})
   if err != nil {
      return fmt.Errorf("write failed: %w", err)
   }
   ctx, cancel := context.WithCancel(context.Background())
   defer cancel()

   go func() {
      _, _ = io.Copy(dest, reader)
      cancel()
   }()
   go func() {
      _, _ = io.Copy(conn, dest)
      cancel()
   }()

   <-ctx.Done()
   return nil
}

运行结果:

{KF$NFJKDC~L6V6@JHZJV6.png