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. 编译+运行: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不可以。

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
    )
    

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
}

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
    }
    
    
  3. 二级指针

    var a int = 1
    var p = &a
    var pp **int = &p
    

7、defer关键字

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

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

    defer println("1")
    defer println("2")
    // 结果为2 1
    
  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)  {
       
    }
    
  2. slice:定义的时候不要指定长度,会自己扩容

    func main() {
       var a []int
       b := []int{1, 2}
       // 调用函数,数组传参是引用传递,在其他函数中修改值,会影响原来的值
       toString(b)
    }
    func toString(myArray int) {
    
    }
    
  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++ {
          
       }
    }
    
  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)
    
    
  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)
    
  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)
    

9、map

map传参也是引用传递

  1. 定义map

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

    myMap1 := make(map[string]string)
    // 增加
    myMap1["a"] = "one"
    // 修改
    myMap1["a"] = "two"
    // 删除
    delete(myMap1, "a")
    

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";
    
}

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)
}

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
}

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{"狗狗"})
}

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)
    
    }
    
  2. 断言

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

15、反射

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

  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)
       }
    }
    

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)
       }
    }
    
  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)
    }
    

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)
}

4、channel和select

一次性监听多个channel

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

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
    • 自动下载:在运行项目的时候会自动下载
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值