这是我参与「第三届青训营 -后端场」笔记创作活动的的第1篇笔记。
[青训营] day1-Go基础
1.1 Go语言的特性
-
高性能、高并发
- 语法简单、学习曲线平缓
- 丰富的标准库
- 完善的工具链
- 静态链接
- 快速编译
- 跨平台
- 垃圾回收
1.2 一些语法注意点
Go的语法形式其实和C/C++有很多相似之处。但是也存在着一些不同,接着让我们来看一看吧。
-
if……else……语句
- if后面没有括号,但是如果你写了括号的话,在保存的时候编译器会直接帮你去掉。
- if后面必须加花括号 {} 不能省略
-
for循环语句
-
Go中没有while、do while等循环,只有唯一的for循环。
-
for后面什么也不写代表一个死循环。
-
循环中可以用break跳出或continue继续循环
//三种for循环的表现形式 for { fmt.Print("loop") break } //result:loop for j := 7; j < 9; j++ { fmt.Print(j) } //result:78 for i <= 3 { fmt.Print(i) i = i + 1 } //result:123
-
-
switch
- case后面不需要加()
- case结尾不用加break
switch a { case 1: fmt.Println("one") case 2: fmt.Println("two") default: fmt.Println("other") } -
切片
- 切片可以任意更改为长度
- 可以用make来创建一个切片,可以像数组一样去取值,用append来追加元素
- 初始化时也可以指定长度
- 可以像Python一样切片操作,但是不支持负数索引
//切片初始化:make([]string,len) s := make([]string, 3) s[0] = "a" s[1] = "b" s[2] = "c" fmt.Println("get:", s[2])// fmt.Println("len:", len(s)) s = append(s, "d") s = append(s, "e", "f") fmt.Println(s) c := make([]string, len(s)) copy(c, s) fmt.Println(c) fmt.Println(s[2:5]) fmt.Println(s[:5]) fmt.Println(s[2:]) good := []string{"g", "o", "o", "d"} fmt.Println(good) -
map
- 可称哈希或者字典
- 可以用make创建一个空map,一个是key类型,另一个value类型
- 是完全无序,随机顺序输出
m := make(map[string]int) m["one"] = 1 m["two"] = 2 fmt.Println(m) //map[one:1 two:2] fmt.Println(len(m)) //2 fmt.Println(m["one"]) //1 fmt.Println(m["unknow"]) //0 r, ok := m["unknow"] fmt.Println(r, ok) //0 false delete(m, "one") m2 := map[string]int{"one": 1, "two": 2} var m3 = map[string]int{"one": 1, "two": 2} fmt.Println(m2, m3) //map[one:1 two:2] map[one:1 two:2] -
range
-
可以用来快速遍历
-
遍历时对于数组返回有两个值,第一个是索引,第二个是对应位置的值。如果不需要索引的话,可以用下划线来忽略
func main() { nums := []int{2, 3, 4} sum := 0 for i, num := range nums { sum += num if num == 2 { fmt.Println("index", i, "num:", num) //index 0 num: 2 } } fmt.Println(sum) //9 m := map[string]string{"a": "A", "b": "B"} for k, v := range m { fmt.Println(k, v) //a A; b B } for k := range m { fmt.Println("key", k) // key a; key b } }
-
-
函数
func add(a int, b int) int { return a + b } func add2(a, b int) int { return a + b } func exists(m map[string]string, k string) (v string, ok bool) { v, ok = m[k] return v, ok } func main() { res := add(1, 2) fmt.Println(res) //3 v, ok := exists(map[string]string{"a": "A"}, "a") fmt.Println(v, ok) //A true } -
指针
- 用于传入参数进行修改
func add3(n int) { n += 2 } func add3ptr(n *int) { *n += 2 } func main() { n := 5 add3(5) fmt.Println(n) //5 add3ptr(&n) fmt.Println(n) //7 } -
结构体
- 带类型的字段集合
- 可以用结构体的名称去初始化一个结构体变量,构造时需要传入每个字段的初始值
- 也可以用键值对的方式去指定初始值,对其中一部分字段进行初始化
- 结构体支持指针,能够实现对结构体的修改,也可以在某些情况下避免一些大结构体的拷贝开销
type user struct { name string password string } func main() { a := user{name: "Dorri", password: "12345"} b := user{"Dorri", "12345"} c := user{name: "Dorri"} c.password = "12345" var d user d.name = "Dorri" d.password = "12345" fmt.Println(a, b, c, d)//{Dorri 12345} {Dorri 12345} {Dorri 12345} {Dorri 12345} fmt.Println(checkPassword(a, "haha")) //false fmt.Println(checkPassword2(&a, "12345")) //true } func checkPassword(u user, password string) bool { return u.password == password } func checkPassword2(u *user, password string) bool { return u.password == password } -
错误处理
- 在函数里,我们可以在那个函数的返回值类型里面,后面加一个error,就代表这个函数可能会返回错误。
- 在函数实现的时候,return需要同时return两个值,要么就是如果出现错误的话,那么可以return nil和一个error,那么返回原本的结果和nil。
type user2 struct { name string password string } func findUser(users []user2, name string) (v *user2, err error) { for _, u := range users { if u.name == name { return &u, nil } } return nil, errors.New("not found") } func main() { u, err := findUser([]user2{{"Dorri", "12345"}}, "Dorri") if err != nil { fmt.Println(err) return } fmt.Println(u.name) //Dorri if u, err := findUser([]user2{{"Dorri", "12345"}}, "li"); err != nil { fmt.Println(err) //not found return } else { fmt.Println(u.name) } } -
JSON
- 对于一个已有的结构体,只需要保证每字段的第一个字母是大写,也就是公开字段
- 用JSON.marshaler去序列化,编程一个JSON的字符串
- 序列化之后的字符串能够用JSON.unmarshaler去反序列化到一个空的变量里面
- 大写字母开头
1.3实战
2.在线字典
遇到的问题:
控制台出现如下的问题。问题在于这个项目我们需要在,终端中运行。
*解决如下*:
-
SOCKS5 代理介绍
-
socks5协议是代理协议,协议是明文传输
-
作用:某些企业为了保证安全性,有很严格的防火墙策略,副作用是访问某些资源会很麻烦,socks5相当于在防火墙开了个扣子,让授权的用户可以通过单个端口去访问内部所有资源。
-
socks5代理-原理
-
- 正常浏览器访问一个网站,如果不经过代理服务器的话,就是先和对方的网扎建立起TCP连接,然后三次握手,握手完之后发起一个HTTP请求,然后服务返回HTTP响应。
- 正常浏览器访问一个网站,设置代理服务器的话,首先是浏览器和socks5代理建立TCP连接,代理再和真正的服务器建立TCP连接。这里我们可以分成四个阶段,握手阶段,认证阶段,请求阶段,relay阶段。
- 第一阶段:握手阶段,浏览器会向socks5代理发送请求,包的内容包括一个协议的版本号,还有支持的认证的种类,socks5服务器会选中一个认证方式,返回给浏览器如果返回的是00的话就代表不需要认证,返回其他类型的话会开始认证流程,这里我们就不对认证流程进行概述。
- 第三阶段:请求阶段,认证通过之后浏览器会socks5服务器发起请求欧。主要信息包括版本号请求的类型,一班主要是connection请求,就代表代理服务器要和某个域名或者某个IP地址某个端口建立TCP连接。代理服务器收到响应之后,会真正好人后端服务器建立连接,然后返回一个响应。
- 第四阶段:rely阶段。此时浏览器会发送正常发送请求,然后代理服务器接受到请求之后,会直接把请求转换成真正的服务器上。然后如果真正的服务器以后返回响应的话,那么也会把请求转发到浏览器