Go

Go

https://www.bilibili.com/video/BV1zR4y1t7Wj?t=9.53

Go语言数据类型转换 (biancheng.net)

一、简介

  • 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
  • 采用Go Modules后,下载的第三方库位于GOPATH/pkg/mod

  • 常见命令

    1
    2
    3
    4
    go 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

  • 初始化:变量一旦声明就会全部自动初始化

  • 变量声明:

    • 标准格式

      1
      var 变量名 变量类型
    • 批量格式

      1
      2
      3
      4
      var (
      a int
      b string
      )
    • 简短格式

      不能提供数据类型,且只能在函数内部

      注意,这种方式要求变量必须未被声明过

      1
      名字 := 表达式
  • 匿名变量

    匿名变量_不能再后序代码中使用,不会占用内存空间

  • 作用域

    • 局部变量

      函数内的局部变量可以和全局变量名称相同,但是会优先考虑局部变量

    • 全局变量

      全局变量必须以var关键词开头 如果想在外部包中使用,则首字母必须大写

    • 形式参数

      就是定义函数时函数名后面括号中的变量,形式参数会作为函数的局部变量来使用

2.2 流程控制

  • 判断语句

    1
    2
    3
    4
    5
    if a>b {
    qqq
    }else {
    yyy
    }
  • 分支语句

    1
    2
    3
    4
    5
    switch var1 {
    case v1: xxx
    case vv2: yyy
    default: zzz
    }
  • 循环语句

    1
    2
    3
    for i:=0,i<10,i++ {
    xxx
    }

2.2 函数

  • 普通函数

    1
    2
    3
    func 函数名(参数) [返回值类型]{

    }

    例-单个返回值:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    func 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
    10
    func 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
    17
    package 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
    11
    type 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
    9
    var tom struct {
    age int
    name string
    email string
    }
    //变量赋值
    tom.name = "qy"
    tom.age = 19
    fmt.Println(tom.name)
  • 结构体初始化

    1
    2
    3
    4
    5
    tom := Person{
    age: 0,
    name: "qy",
    email: "",
    }
  • 结构体指针

    1
    2
    var p *Person = &tom
    fmt.Printf("%p\n", p)

2.5 包

  • 为了让本包中的函数能够被其他包调用,函数名的首字母需要大写。
  • 值得注意的是,包名和文件夹名不一定相同。在import的地方写的是你的文件名,在调用的时候使用的是包名。
  • 在import时,默认首先在GOROOT下的src找,然后从GOPATH下的src找
  • 如果要编译成一个可执行程序文件,就需要将这个包声明为main;如果是写一个库,包名随意

2.6 数组/切片

数组和切片是类似的。数组的长度固定,切片的长度不固定,具有动态长度,可以通过append动态增加切片的长度。

另外,他们的初始化方式也有所不同。

  • 数组

    1
    2
    var arr [3]int         // 声明一个长度为3的整型数组
    arr = [3]int{1, 2, 3} // 初始化数组
  • 切片

    1
    2
    3
    var slice []int        // 声明一个切片
    slice = []int{1, 2, 3} // 使用切片字面量初始化切片
    slice = append(slice, 4, 5, 6) // 使用append函数向切片追加元素

三、并发

默认情况下,在main线程执行完毕后,所有的协程不管怎样都会终止。

如果乱用协程,很可能出现资源竞争的问题,我们有三种解决方案:

  1. 互斥锁

    1
    2
    3
    var 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
    13
    func 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
    22
    func 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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
package main

import (
"flag"
"fmt"
)

var (
age int
)

func init() {
fmt.Print("init")
flag.IntVar(&age, "a", 19, "your age")
}
func main() {
fmt.Print("main")
flag.Parse()
fmt.Print(age)
}

/**
C:\Users\28185\Desktop\goLearn>main.exe -a 123
123
*/

值得注意的是,flag.Parse必须在所有选项定义后调用,且flag.Parse后不能定义新的选项.

5.2 Msgp

msgp是Message Pack的缩写,是一种二进制序列化格式。

六、代理

1
2
3
4
5
# 配置代理
go env -w GOPROXY=https://goproxy.cn,direct
go env -w GOSUMDB=goproxy.cn/sumdb/sum.golang.org
# 取消代理
go env -u GOPROXY

Go
https://d4wnnn.github.io/2023/01/12/Dev/Go/
作者
D4wn
发布于
2023年1月12日
许可协议