Go
Go
https://www.bilibili.com/video/BV1zR4y1t7Wj?t=9.53
一、简介
Go无类和继承的概念 通过接口实现多态性
Docker是根据go开发的
go是编译型语言 自带编译器
标准库:
在 Windows 下,标准库的位置在Go语言根目录下的子目录 pkg_amd64 中;在 Linux 下,标准库在Go语言根目录下的子目录 pkgamd64 中(如果是安装的是 32 位,则在 linux_386 目录中)。一般情况下,标准包会存放在
GOOS$GOARCH/ 目录下。 go语言自带垃圾回收
包:
- 包名可以与目录名不同
- 一个go程序必须有且仅有一个main包
- 导入的包不能含有代码中没有用到的包
go常见指令:
- go run在编译后直接运行程序 不会生成可执行文件
- go build编译
Go Path与Go Modules的关系如何?
- 最早的时候,Go所有的库都放在GOPATH这个目录下,很不方便管理。我们可以通过
go env GOPATH来查看此目录。在这个阶段,我们可以给每个项目设置不同的GOPATH,否则所有的项目还有第三方库都要通过go get xxx下载到GOPATH\src下,项目混乱不堪。即使设置了不同的GOPATH,仍然有很明显的缺点,就是会下载重复的依赖,而且第三方库也要和我们的项目源码放在一起。 - 为了解决
GOPATH的缺点,Go Modules横空出世,类似Java里面的Maven,把所有的第三方库下载在一个统一的文件夹,然后项目去调用即可。
Go Modules相关知识
在Go的环境变量中,有一个变量
GO111MODULE负责Go Modules的开关- auto:若当前项目不在
GOPATH下且当前或上一层文件夹有go.mod则使用Go Modules - on:开启
Go Modules - off:关闭
Go Modules
- auto:若当前项目不在
采用
Go Modules后,下载的第三方库位于GOPATH/pkg/mod下常见命令
1
2
3
4go mod init:初始化go mod, 生成go.mod文件,后可接参数指定 module 名
go mod download:手动触发下载依赖包到本地cache(默认为$GOPATH/pkg/mod目录)
go mod graph: 打印项目的模块依赖结构
go mod tidy :添加缺少的包,且删除无用的包
二、基本语法
2.1 变量
变量基本类型:
bool
string
int int8 int16、int32、int64
uint、uint8、uint16、uint32、uint64、uintptr
byte // uint8 的别名
rune // int32 的别名 代表一个 Unicode 码
float32、float64
complex64、complex128
初始化:变量一旦声明就会全部自动初始化
变量声明:
标准格式
1var 变量名 变量类型批量格式
1
2
3
4var (
a int
b string
)简短格式
不能提供数据类型,且只能在函数内部
注意,这种方式要求变量必须未被声明过
1名字 := 表达式匿名变量
匿名变量
_不能再后序代码中使用,不会占用内存空间作用域
局部变量
函数内的局部变量可以和全局变量名称相同,但是会优先考虑局部变量
全局变量
全局变量必须以var关键词开头 如果想在外部包中使用,则首字母必须大写
形式参数
就是定义函数时函数名后面括号中的变量,形式参数会作为函数的局部变量来使用
2.2 流程控制
判断语句
1
2
3
4
5if a>b {
qqq
}else {
yyy
}分支语句
1
2
3
4
5switch var1 {
case v1: xxx
case vv2: yyy
default: zzz
}循环语句
1
2
3for i:=0,i<10,i++ {
xxx
}
2.2 函数
普通函数
1
2
3func 函数名(参数) [返回值类型]{
}例-单个返回值:
1
2
3
4
5
6
7
8
9
10func main() {
fmt.Println(test(1, 2))
}
func test(a int, b int) int {
if a > b {
return a
} else {
return b
}
}例-多个返回值:
1
2
3
4
5
6
7
8
9
10func main() {
fmt.Println(test(1, 2))
}
func test(a int, b int) (int, int) {
if a > b {
return a, b
} else {
return b, a
}
}方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17package main
import "fmt"
type Person struct {
name string
age int
}
func main() {
var p Person
p.name = "qy"
p.test()
}
func (p Person) test() {
fmt.Println(p.name)
}
2.3 结构体
go没有面向对象的概念,但是可以用结构体来实现
普通结构体
1
2
3
4
5
6
7
8
9
10
11type Person struct {
age int
name string
email string
}
//声明结构体类型的变量
var tom Person
//变量赋值
tom.name = "qy"
tom.age = 19
fmt.Println(tom.name)匿名结构体
1
2
3
4
5
6
7
8
9var tom struct {
age int
name string
email string
}
//变量赋值
tom.name = "qy"
tom.age = 19
fmt.Println(tom.name)结构体初始化
1
2
3
4
5tom := Person{
age: 0,
name: "qy",
email: "",
}结构体指针
1
2var p *Person = &tom
fmt.Printf("%p\n", p)
2.5 包
- 为了让本包中的函数能够被其他包调用,函数名的首字母需要大写。
- 值得注意的是,包名和文件夹名不一定相同。在import的地方写的是你的文件名,在调用的时候使用的是包名。
- 在import时,默认首先在GOROOT下的src找,然后从GOPATH下的src找
- 如果要编译成一个可执行程序文件,就需要将这个包声明为main;如果是写一个库,包名随意
2.6 数组/切片
数组和切片是类似的。数组的长度固定,切片的长度不固定,具有动态长度,可以通过append动态增加切片的长度。
另外,他们的初始化方式也有所不同。
数组
1
2var arr [3]int // 声明一个长度为3的整型数组
arr = [3]int{1, 2, 3} // 初始化数组切片
1
2
3var slice []int // 声明一个切片
slice = []int{1, 2, 3} // 使用切片字面量初始化切片
slice = append(slice, 4, 5, 6) // 使用append函数向切片追加元素
三、并发
默认情况下,在main线程执行完毕后,所有的协程不管怎样都会终止。
如果乱用协程,很可能出现资源竞争的问题,我们有三种解决方案:
互斥锁
1
2
3var lock sync.Mutex
lock.Lock()
lock.Unlock()
3.1 并发简述
将
go放到被调用的函数前,函数执行时便会作为一个独立的线程并发通信
通道Channel
一个channel只能传递一种类型的值
四、连接MongoDB
- 上下文
- 对
mongo的任何操作都离不开一个上下文环境contex.background:创建默认的,无限期的上下文context.todo:
select语句类似switch,只能用于通道操作;select语句会监听所有指定的通道的操作,一旦一个通道准备好就会执行响应的代码块
当select为空的时候,有一个作用是可以防止程序在创建完协程后立即退出
defer:常用于资源的释放和异常的捕获,defer后的语句会在return后执行
1
2
3
4
5
6
7
8
9
10
11
12
13func CopyFile(dstName, srcName string) (written int64, err error) {
src, err := os.Open(srcName)
if err != nil {
return
}
dst, err := os.Create(dstName)
if err != nil {
return
}
dst.Close()
src.Close()
return
}当有异常,会直接return,此时资源未释放
panic:类似Exception,是用来抛出异常的,recover用来恢复异常,比如
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22func main() {
f()
fmt.Println("Returned normally from f.")
}
func f() {
defer func() {
if r := recover(); r != nil {
fmt.Println("Recovered in f", r)
}
}()
fmt.Println("Calling g.")
g(0)
fmt.Println("Returned normally from g.")
}
func g(i int) {
fmt.Println("Printing in g", i)
panic(i)
fmt.Println("After panic in g", i)
}数组:
1
var balance = [5]float32{1000.0, 2.0, 3.4, 7.0, 50.0}time模块
time.NewTicker:Ticker是周期触发的定时器,可以理解为特殊的通道,每隔一段时间就往这个通道发送时间
context:通过实例理解Go标准库context包 | Tony Bai
结构体中若变量类型是指针或slice或map,必须要用make,不然不会分配空间
管道:v, ok := <-ch中的ok代表是否读到数据
RPC:
通俗理解RPC:客户端可以像调用本地程序一样调用远程服务器的应用程序
bson:
bson.D:bson文档的有序表示
bson.M:bson.M与顺序无关
五、第三方库
5.1 Flag
flag用于解析命令行选项
1 | |
值得注意的是,flag.Parse必须在所有选项定义后调用,且flag.Parse后不能定义新的选项.
5.2 Msgp
msgp是Message Pack的缩写,是一种二进制序列化格式。
六、代理
1 | |