• golang入门


    1、配置环境变量

    1. 下载(尽量下载压缩包的zip):https://golang.google.cn/dl/

    2. 配置GOROOT,值为go安装路径

      在这里插入图片描述

    3. 配置GOPATH:值为你项目或者练习项目的路径,自己创建,这里我是在golang安装目录在新建一个空的olangWorkSpace文件下。

      在这里插入图片描述

    4. 配置path

      在这里插入图片描述

    在这里插入图片描述

    1. 测试,在命令行在输入go env 进行测试GOROOT和GOPATH配置的对不对

      在这里插入图片描述

    2、Hello

    package main
    
    import "fmt"
    
    func main() {
       fmt.Println("hello")
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    1. 编译+运行:go run xxx.go
    2. 先编译再运行:
      • go build xxx.go
      • ./xxx.go

    3、声明变量

    1. var a int (有默认值,默认值为02. var a int = 100
    3. var a = 100
    4. a := 100
    5. var a, b int = 1, 2
    6. var(
    	a int = 100
        b string = "b"
    )
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    注:单个变量声明中,1、2、3是可以声明全局变量,4不可以。

    4、const和iota

    1. 定义常量:const a := 1

    2. iota使用在const枚举中

      const (
          //可以在const()添加一个关键字iota,每行的iota都会累加1,第一行的iota的默认值是0
      a, b = iota+1, iota+2 // iota = 0, a = iota + 1, b = iota + 2, a = 1, b = 2
      c, d // iota = 1,c = iota + 1, d = iota + 2,c = 2, d = 3
      e, f //iota = 2, e = iota + 1, f = iota + 2,e = 3, f = 4
      g, h // iota * 2,iota *3 ll iota = 3, g = iota * 2, h = iota * 3,g = 6, h = 9
      i, k //iota = 4, i = iota * 2, k = iota * 3 , i = 8, k = 12
      )
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8

    5、函数和导包

    1.函数

    1. func f1(a int, b int) int {
        return a+b
    }
    2. func f2(a int, b int) (int, int) {
        return a, b
    }
    3. func f3(a int, b int) (r1 int, r2 int) {
        r1 = a * 10
        r2 = b * 10
        return
    }
    4. func f4(a int, b int) (r1, r2 int) {
        r1 = a * 10
        r2 = b * 10
        return
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    go执行流程

    在这里插入图片描述

    2.导包

    1. import “fmt”:直接用fmt去调用方法。
    2. import f “fmt”:给fmt包区别,通过别名调用方法。
    3. import _“fmt”:匿名,无法使用当前包的方法,但是会执行当前包内部的init()方法。
    4. import .“fmt”:将fmt的全部方法全部导入到本包中,直接通过方法名就可以使用理:Println()。不推荐使用

    6、指针

    指针存的是地址,并且可以直接修改地址里的值,java改引用类型的值并不是改地址里的值,而且赋值另外一个值的地址。

    1. &是传地址、*是取地址

    2. 使用

      package main
      
      func main() {
      	var a int = 1
      	var b int = 2
      	swap(&a, &b)
      	println(a)
      	println(b)
      }
      func swap(pa *int, pb *int) {
      	var temp int = *pa
      	*pa = *pb
      	*pb = temp
      }
      
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
    3. 二级指针

      var a int = 1
      var p = &a
      var pp **int = &p
      
      • 1
      • 2
      • 3

    7、defer关键字

    1. defer是最后执行的,有点像java的final

      defer println("1")
      println("2")
      //结果为2 1
      
      • 1
      • 2
      • 3
    2. 多个defer是以压栈的形式执行的

      defer println("1")
      defer println("2")
      // 结果为2 1
      
      • 1
      • 2
      • 3
    3. defer晚与return执行

      先执行return再执行defer

    8、数组和切片slice(动态数组)

    1. 数组:定义的时候要指定长度

      func main() {
         // 定义固定长度数组,默认值为0
         var a [10]int
         b := [2]int{1,2};
         // 调用函数,传参只能传长度一样的形参,并且数组传参是值传递,在其他函数中修改值,不影响原来值
         toString(b)
      }
      func toString(myArray [2]int)  {
         
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
    2. slice:定义的时候不要指定长度,会自己扩容

      func main() {
         var a []int
         b := []int{1, 2}
         // 调用函数,数组传参是引用传递,在其他函数中修改值,会影响原来的值
         toString(b)
      }
      func toString(myArray int) {
      
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
    3. 遍历数组或者slice

      // 如果是数组行参要指定长度,func myfor(nums [len]int){}
      func myfor(nums []int) {
         // 1.第一种遍历
         for key, value := range nums {
            fmt.Println(key, value)
         }
         // 第二种遍历
         for i := 0; i < len(nums); i++ {
            
         }
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
    4. slice四种定义方式

      // 1、初始化长度和默认值
      slice := []int{1, 2, 3}
      
      
      // 2、声明一个slice,但是并不分配空间,这个时候长度为0,需要使用make方法进行扩容
      var slice []int
      slice = make([]int, 3)
      
      // 3、声明一个slice,同时初始化空间长度
      var slice []int = make([]int, 3)
      
      // 4、
      slice := make([]int, 3)
      
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
    5. slice追加

      // 创建一个长度为2容量为5的切片make(int[], len, cap)
      s := make([]int, 2, 5)
      // 追加的时候如果len=cap,则会进行扩容,每次扩容的长度为cap
      s = append(s, 1)
      // 输出为3 5 [0 0 1]
      fmt.Println(len(s), cap(s), s)
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
    6. slice切片:类似python的切片,注意slice的切片是引用传递

      // 创建一个长度为2容量为5的切片make(int[], len, cap)
      s := make([]int, 2, 5)
      // 切完出来的数据是引用传递,修改新值会影响原来的值
      s1 := s[0:2]
      s1[0] = 100
      //结果为[100 0] [100 0]
      fmt.Println(s, s1)
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7

    9、map

    map传参也是引用传递

    1. 定义map

      // 第一种声明方式,使用map进行创建,可以传入容量,没有的话默认为1,每次扩容的长度为容量
      myMap1 := make(map[int]string)
      
      // 第二种声明方式,声明的时候初始化赋值
      myMap2 := map[int]string{
          0: "one",
          1: "two"
      }]
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
    2. map使用

      myMap1 := make(map[string]string)
      // 增加
      myMap1["a"] = "one"
      // 修改
      myMap1["a"] = "two"
      // 删除
      delete(myMap1, "a")
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7

    10、struct结构

    相当于java的class

    type Book struct {
        title string
        author string
    }
    // 这样传递是值拷贝,在函数中修改book,不会影响原来的book
    func toString(book Book){}
    func main() {
        var book1 Book;
        book1.title = "a";
        bokk1.author = "b";
        
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    11、封装

    func main() {
    	hero := Hero{"吕竟", 100}
    	hero.SetName("吕竟1")
    	hero.Show()
    }
    
    type Hero struct {
    	Name  string
    	level int
    }
    
    func (this *Hero) GetName() string {
    	return this.Name
    }
    func (this *Hero) SetName(newName string) {
    	this.Name = newName
    }
    func (this *Hero) Show() {
    	fmt.Println("name: ", this.Name, "level: ", this.level)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    12、继承

    func main() {
       z := Z{F{"lv", "nan"}, 10}
       z.Show()
    }
    
    // 定义父类
    type F struct {
       name string
       sex  string
    }
    
    // 父类方法
    func (this *F) Show() {
       fmt.Println("name: ", this.name, "sex: ", this.name)
    }
    // 重写父类方法
    func (this *Z) Show() {
       fmt.Println("我是子类")
    }
    // 子类继承父类
    type Z struct {
       F
       age int
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    13、接口和多态

    注意:子类要实现父类的所有接口方法,才算实现了父类接口

    // 定义一个接口
    type AnimalF interface {
       Sleep()
       Call() string
    }
    
    // 定义一个子类狗实现接口
    type Dog struct {
       name string
    }
    
    func (this *Dog) Sleep() {
       fmt.Println("狗在睡觉")
    }
    
    func (this *Dog) Call() string {
       return "旺旺"
    }
    
    // 定义一个子类猫实现接口
    type Cat struct {
       name string
    }
    
    func (this Cat) Sleep() {
       fmt.Println("猫在睡觉")
    }
    
    func (this Cat) Call() string {
       return "喵喵"
    }
    
    // 多态
    func getAnimal(f AnimalF) {
       f.Sleep()
    }
    
    func main() {
       animal := &Cat{"喵酱"}
       animal.Sleep()
       getAnimal(&Cat{"猫猫"})
       getAnimal(&Dog{"狗狗"})
    }
    
    • 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
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43

    14、万能类型和类型断言

    万能类型interface{},go的所有类型都实现基础了interface{}类型

    1. 万能类型

      func show(o interface{}) {
         fmt.Println(o)
      }
      
      type Book struct {
         name string
      }
      
      func main() {
         book := Book{"书籍"}
         show("a")
         show(1)
         show(book)
      
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
    2. 断言

      // value是arg的值,ok是true或false
      value, ok := arg.(string)
      
      • 1
      • 2

    15、反射

    1. 每一个变量都有两个指针pair,一个类型,一个值。

    2. 使用

      import (
         "fmt"
         "reflect"
      )
      
      func show(o interface{}) {
         fmt.Println(o)
      }
      
      type Book struct {
         Name  string
         Price int
      }
      
      func (this Book) Call() {
         fmt.Println(this)
      }
      
      func main() {
         book := Book{"书籍", 10}
         // 反射获得类型
         bookType := reflect.TypeOf(book)
         // 反射获得值
         bookValue := reflect.ValueOf(book)
         fmt.Println(bookType.Name(), bookValue)
      
         // 反射获得内部属性
         for i := 0; i < bookType.NumField(); i++ {
            // 获得属性名
            field := bookType.Field(i)
            value := bookValue.Field(i).Interface()
            fmt.Println(field.Name, value)
         }
      
         // 反射获得方法
         for i := 0; i < bookType.NumMethod(); i++ {
            m := bookType.Method(i)
            fmt.Println(m.Name)
         }
      }
      
      • 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
      • 26
      • 27
      • 28
      • 29
      • 30
      • 31
      • 32
      • 33
      • 34
      • 35
      • 36
      • 37
      • 38
      • 39
      • 40

    16、标签

    1. 变量名 数据类型 key: value key: value ....

    2. 使用reflect.TypeOf(&变量).Elem()的时候记得传参数用指针

      type Book struct {
         Name  string `info:"吕竟" doc:"是帅哥"`
         Price int    `info:"10"`
      }
      
      func (this Book) Call() {
         fmt.Println(this)
      }
      
      func main() {
         b := Book{"吕", 1}
         t := reflect.TypeOf(&b).Elem()
         // 通过反射获得标签
         for i := 0; i < t.NumField(); i++ {
            taginfo := t.Field(i).Tag.Get("info")
            tagdoc := t.Field(i).Tag.Get("doc")
            fmt.Println(taginfo, "   ", tagdoc)
         }
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
    3. 标签在json中的应用

      type Book struct {
         Name  string `json:"name"`
         Price int    `json:"rmb"`
      }
      func main() {
         b := Book{"红楼梦", 1}
         // 结构体转json
         jsonStr, err := json.Marshal(&b)
         if err != nil {
            fmt.Println("错误")
            return
         }
         fmt.Println(b)
         fmt.Println(string(jsonStr))
      
         // json转结构体
         b1 := Book{}
         json.Unmarshal(jsonStr, &b1)
         fmt.Println(b1)
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20

    17、协程(goroutin)

    1. 进程/线程的数量越多,切换成本越大,也就越浪费。
    2. 并且线程和进程都会占用内存,在java中,一个线程占内存的1M 。
    3. 线程分为内核空间和用户空间,协程则是:一个内核空间绑定cpu,并且通过协程调度器绑定用户空间中的多个协程,这样的话就会形成,cpu操作的只有一个线程,而这个线程里又有多个协程(用户线程),这样就可以减少cpu的线程的切换

    在这里插入图片描述

    在这里插入图片描述

    在这里插入图片描述

    1. GMP模型

      在这里插入图片描述

    1、调度器设计策略

    1、复用线程

    1、work stealing机制
    1. 当M1正在处理G1协程的时候,这个时候G1可能在阻塞,而这个时候M1的P队列还有其他协程在正在等待,那么这个时候G3就会移到M2的P队列中进行处理

    在这里插入图片描述

    2、hand off机制
    1. 当m1正在阻塞的时候,而m2也有队列在执行,那么则会新创建一个线程Threadm3,然后把m1的本地队列移到m3中进行执行。而且这个时候m1的G1如果还会执行的话会被移到其他线程中,如果不执行则会进行睡眠或者销毁

    在这里插入图片描述

    在这里插入图片描述

    2、利用并行

    GoMAXPROCS限定的P的个数=CPU核数/2

    3、抢占

    在这里插入图片描述

    4、全局G队列

    1. 基于work stealing机制,从全局偷取

      在这里插入图片描述

    2、使用

    1. 在前面加一个go关键字。
    2. 要停止的话加runtime.Goexit()

    18、Channel

    1、创建channel

    1. make(chan Type)=make(chan Type, 0)
    2. make(chan Type, capacity)

    2、使用

    1. channel <- value 发送value到channel
    2. <-channel 接收并将其丢弃
    3. x := <-channel 从channel中接收数据,并赋值给x
    4. x, ok := <-channel 功能同上,同时检查通道是否已关闭或者是否为空
    5. close(channel) 关闭channel

    3、channel和range

    会不断去监听channel,如果channel有值则会执行range把值取出

    for data := range c {
        fmt.Println(data)
    }
    
    • 1
    • 2
    • 3

    4、channel和select

    一次性监听多个channel

    select {
        case <- chan1:
        	// 如果chan1成功读到数据,则进行该case处理语句
        case chan2 <- 1:
        	// 如果成功向chan2写入数据,则进行该case处理语句
        default:
        	// 如果上面都没有成功,则进入default处理流程
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    19、Go Modules

    1、go mod命令

    1. go mod init 项目名字:生成go.mod文件
    2. go mod download:下载go.mod文件中指名的所有依赖
    3. go mod tidy:整理现有的依赖
    4. go mod graph:查看现有的依赖结构
    5. go mod edit:编辑go.mod文件
    6. go mod vendor:导出项目所有的依赖到vendor目录
    7. go mod verify:校验一个模块是否被篡改过
    8. go mod why:查看为什么需要依赖某模块

    2、go mod环境变量

    1. GO111MODULE
      • 是否开启go modules模式
      • 建议go B1.11之后,都设置为on
    2. GOPROXY
      • 项目的第三方依赖库的下载地址
      • 建议设置国内的地址
        • 阿里云:https://mirrors.aliyun.com/goproxy/
        • 七牛云:https://goproxy.cn,direct
      • direct:用于指示Go回源到模板版本的源地址去抓取(比如github等)
    3. GOSUMDB
      • 用来校验拉取的第三方库是否是完整的
      • 默认也是国外的网站,如果设置了GOPROXY,这个就不用设置了。
    4. GONOPROXY
      • 通过设置GOPRIVATE即可
      • 通过设置GOPRIVATE即可
    5. GOPRIVATE
      • 通go env -W GOPRIVATE=“git.example.com,github.com/aceld/zinx”
      • 表示git.example.com和github.com/aceld/zinx是私有仓库,不会进行GOPROXY下载和校验
      • go env -w GOPRIVATE=“*.example.com”
      • 表示所有模块路径为example.com的子域名,比如git.example.com或者hello.example.com都不进行GOPROXY下载和校验。

    3、使用go mod

    1. 开启go mod: go env -w GO111MODULE=on
    2. 修改代理地址:go env -w GOPROXY=https://goproxy.cn,direct
      • 阿里云:https://mirrors.aliyun.com/goproxy/
      • 七牛云:https://goproxy.cn,direct
    3. 在项目中初始化Go:go mod init xxxname
    4. 下载依赖:
      • 手动下载具体的依赖:go get xxxx
      • 自动下载:在运行项目的时候会自动下载

    国外的网站,如果设置了GOPROXY,这个就不用设置了。
    4. GONOPROXY

    • 通过设置GOPRIVATE即可
    • 通过设置GOPRIVATE即可
    1. GOPRIVATE
      • 通go env -W GOPRIVATE=“git.example.com,github.com/aceld/zinx”
      • 表示git.example.com和github.com/aceld/zinx是私有仓库,不会进行GOPROXY下载和校验
      • go env -w GOPRIVATE=“*.example.com”
      • 表示所有模块路径为example.com的子域名,比如git.example.com或者hello.example.com都不进行GOPROXY下载和校验。

    3、使用go mod

    1. 开启go mod: go env -w GO111MODULE=on
    2. 修改代理地址:go env -w GOPROXY=https://goproxy.cn,direct
      • 阿里云:https://mirrors.aliyun.com/goproxy/
      • 七牛云:https://goproxy.cn,direct
    3. 在项目中初始化Go:go mod init xxxname
    4. 下载依赖:
      • 手动下载具体的依赖:go get xxxx
      • 自动下载:在运行项目的时候会自动下载
  • 相关阅读:
    集体唱好混动技术,传统车企最后的倔强?
    百度推广助手遇到重复关键字,验证错误,怎么一键删除多余的
    LQ0171 分小组【程序填空】
    ROS系统使用usb_cam摄像头
    机器学习中的算法--kMeans and DBSCAN
    DML(插入 更新 删除),附代码理解
    【Excel函数】Trim函数删除前后多余的空格
    Docker原理详细剖析-Namespace
    第16章 模板和泛型编程【C++】
    硬件20、嘉立创EDA关闭铺铜的显示(方便查看走线)
  • 原文地址:https://blog.csdn.net/qq_44255146/article/details/127797435