Day 1 Go | 青训营笔记

81 阅读4分钟

这是我参与「第五届青训营 」伴学笔记创作活动的第 1 天

课堂重点

今天学习了两节课,分别是:

  1. Go语言的基础
  2. Go语言的实战案例

基础包含:
  1. Go开发环境的配置,先下载Golang语言,后续再配置Go语言开发环境选择使用VS Code或者 Goland
  2. 基础语法
  3. 标准库函数
  4. go开启协程的方式,以及管道channel的介绍(后续查阅资料进一步学习的)
  5. 三个实战项目(猜数字、命令行字典、socket5代理服务器)

详细介绍

  1. 对于Go语言开发环境,我选择是的VS Code,之前就已经下载了,只需要安装插件即可,外存占用低,也不需要Goland的注册许可证
  2. 对于基础语法中map和slice切片是最为常用也最为重要的数据类型。
    对于map 我们跟我们可以用 make 来创建一个空 map ,这里会需要两个类型,第一个是那个 key 的类型, 另一个是 value 的类型。有其他语言基础会更好理解 我们可以从里面去存储者取出键值对。可以用 delete 从里面删除键值对。golang的map是完全无序的,遍历的时候不会按照字母顺序,也不会按照插入顺序输出,而是随机顺序。
    对于切片,因为 slice 的原理实际上是它有一个它存储了一个长度和一个容量,加一个指向一个数组的指针,在你执行 append 操作的时候,如果容量不够的话,会扩容并且返回新的 slice ,因此在函数之间传递切片的时候,都是引用传递。不用担心会产生局部变量无法操作原切片 3.标准库函数有两个最常用的包分别为:
    strings包中的操作字符串的函数
a :="hello" fmt.PrintIn(strings.Contains(a,"ll")) // true 
fmt.Println(strings.Count(a,"l")) // 2 
fmt.Println(strings.HasPrefix(a,"he")) // true 
fmt.Println(strings.HasSuffix(a,"llo")) // true 
fmt.Println(strings.Index(a,"ll")) //2 
fmt.Println(strings.Join([]string["he","llo"},"-")) // he-llo 
fmt.Println(strings.Repeat(a, 2)) // hellohello1 
fmt.Println(strings.Replace(a,"e","E"-1)) // hEllo 
fmt.Println(strings.Split("a-b-c",*-")) //[a b c] 
fmt.Println(strings.ToLower(a)) //hello 
fmt.Println(strings.ToUpper(a)) //HELLO 
fmt.Println(len(a)) //5

fmt字符串格式的方法

s :="hello" 
n := 123 
p := point(1,2) 
fmt.Println(s,n) // hello 123 
fmt,Println(p) //{1 2} 
fmt.Printf("s=%v\n",s) // s=hello 
fmt.Printf("n=%v\n",n) // n=123 
fmt.Printf("p=%v\n",p) //p = {1 2} 
fmt.Printf("p=%+v\n",p) // p={x:1 y:2} 
fmt.Printf("p=%#v\n",p) // p=main.point{x:1,y:2) 
f := 3.141592653 
fmt.Println(f) //3.141592653 
fmt.Printf( "%.2f\n",f) //3.14

实践练习

猜数字游戏,只是熟悉Go语法。值得注意的是使用的随机数

import (
    "math/rand"
    "time"
)
rand.Seed(time.Now().UnixNano())
secretNumber := rand.Intn(maxNum)

以及使用reader来获取屏幕的输入

import (
	"bufio"
	"os"
	"strconv"
	"strings"
)
reader := bufio.NewReader(os.Stdin)
input, err := reader.ReadString('\n')
if err != nil {
        fmt.Println("错误")
        return
}
input = strings.TrimSuffix(input, "\n")
input = strings.TrimSuffix(input, "\r")//对于不同电脑可能会出现的转义字符,需要去掉
guess, err := strconv.Atoi(input)

命令行字典,更多是的json、抓包和第三方工具的使用
通过获取浏览器的返回的数据包,进行格式解析,运用到命令行字典程序中

curlconverter.com/#go //用于把从浏览器中截取到的curl字符串,生成相应的go代码,用于求取该curl字符串
oktools.net/json2go //可以把JSON转Golang Struct可以接受上述的网站生成代码的数据

再筛选出解析后的数据中需要的字段,最后打印

socket5代理服务器
王克纯大佬的github仓库源码
先了解了socket5代理服务器的原理,以及使用范围

socks5 相当于在防火墙开了个口子,让授权的用户可以通过单个端口去访问内部的所有资源。实际上很多翻墙软件,最终暴露的也是一个 socks5协议的端口。

使用了go语言内置的net包创建一个简易转发服务器,再继续扩展其功能

然后通过客户端对其传输数据,socket5代理服务器进行解析,再去访问真正的服务器,把资源返回,socket5代理服务器再返回资源给客户端
资源返回有个语法,个人认为比较关键:context的WithCancel的使用

ctx, cancel := context.WithCancel(context.Background()) 
defer cancel() 
    go func() { 
    _, _ = io.Copy(dest, reader) 
    cancel() 
}() 
go func() { 
    _, _ = io.Copy(conn, dest) 
    cancel() 
}() 
<-ctx.Done()
  1. WithCancel()函数接受一个 Context并返回其子Context(上图ctx)和取消函数cancel
  2. 新创建协程中传入子Context做参数(上图是匿名函数,自动捕获外部变量),且需监控子Context(上图ctx)的Done通道,若收到消息,则退出,未收到就会阻塞
  3. 需要新协程结束时,调用 cancel 函数,即会往子Context(上图ctx)的Done通道发送消息
  4. 注意:当父Context的 Done() 关闭的时候,子Context的 Done() 也会被关闭